Hack to name unit tests?

Christopher Wright dhasenan at gmail.com
Thu Nov 29 18:03:01 PST 2007


Daniel Keep wrote:
> 
> Christopher Wright wrote:
>> Robert Fraser wrote:
>>> Christopher Wright wrote:
>>>> Robert Fraser wrote:
>>>>> Christopher Wright wrote:
>>>>>> Robert Fraser wrote:
>>>>>>> I'm creating a Flectioned-based way to run unit tests individually
>>>>>>> (it'll be hooked into a front-end, so you can run test suites,
>>>>>>> repeat only failed tests after a code change, etc.)
>>>>>>>
>>>>>>> However, I have run into a problem: unit tests can't be named.
>>>>>>> Right now I have a signature system, but I was wondering if
>>>>>>> there's any hackish way to predictably insert a string into the
>>>>>>> generated object file in a way that users can name unittests. That
>>>>>>> is to say, given a function pointer, is there any way I can scan
>>>>>>> the code to see if a name has been given to the unit test, and if
>>>>>>> so extract that name at runtime?
>>>>>>>
>>>>>>> Ideally, it'd be as easy for the user as something like:
>>>>>>>
>>>>>>> unittest
>>>>>>> {
>>>>>>>    assert(":testName:");
>>>>>>>    // Rest of test goes here...
>>>>>>> }
>>>>>>>
>>>>>>> Right now, I have the associations being done in the front-end I'm
>>>>>>> working on, that scans the code for comments in a particular
>>>>>>> format and associates those with the unit tests. However, that
>>>>>>> ties the unit test executor back-end to the code analysis
>>>>>>> front-end, so I was hoping there's a better way.
>>>>>>>
>>>>>>> Thanks!
>>>>>> class Unittest (string _name, alias _dg) : IUnittest {
>>>>>>    static string name = _name;
>>>>>>    static void delegate() test = _dg;
>>>>>> }
>>>>>>
>>>>>> Usage:
>>>>>> Unittest!("my test for wossname", {
>>>>>>    assert (false, "haven't gotten around to implementing this yet");
>>>>>> });
>>>>>>
>>>>>> Not guaranteed to work.
>>>>>>
>>>>>> Another tactic would be something like:
>>>>>>
>>>>>> class UnittestManager {
>>>>>>    static void registerCurrentTest (string name) {}
>>>>>>    static void endTest (bool success) {}
>>>>>>    static bool performTest () {}
>>>>>> }
>>>>>>
>>>>>> template Unittest (string _name, alias _dg) {
>>>>>>    unittest {
>>>>>>       UnittestManager.registerCurrentTest(_name);
>>>>>>
>>>>>>       // This lets us skip the test if we're just trying
>>>>>>       // to find out what tests there are currently.
>>>>>>       if (UnittestManager.performTest) {
>>>>>>          scope(success) UnittestManager.endTest(true);
>>>>>>          scope(failure) UnittestManager.endTest(false);
>>>>>>          _dg();
>>>>>>       }
>>>>>>    }
>>>>>> }
>>>>>>
>>>>>> mixin Unittest!("my test name", { assert (false, "not yet
>>>>>> implemented"); });
>>>>> Thanks! That's a good idea, but I want something compatible with
>>>>> current unittest {} declarations.
>>>> You already have to modify the tests to insert the name, but you want
>>>> something that works as a decorator inside the unittest. Can your
>>>> unittest runner do a try/catch on a unittest? Then you could have
>>>> something like:
>>>>
>>>> void testName(string name) {
>>>>    if (collectingNames)
>>>>       throw new UnittestNameException(name);
>>>> }
>>>>
>>>> struct NamedTest {
>>>>    Unittest test;
>>>>    string name;
>>>> }
>>>>
>>>> ...
>>>> void main () {
>>>>    NamedTest[] tests;
>>>>    collectingNames = true;
>>>>    foreach (test; getUnittests) {
>>>>        try {
>>>>            test();
>>>>        } catch (UnittestNameException e) {
>>>>            tests ~= NamedTest(test, e.name);
>>>>        }
>>>>    }
>>>>    collectingNames = false;
>>>> }
>>>>
>>>> unittest {
>>>>    testName("blargh");
>>>>    assert (false, "still working on this");
>>>> }
>>> Heh; alright; that's what I was looking for! Thanks!
>> No worries. It's pretty much identical in principle to mocked methods in
>> dmocks, except for using exceptions to pass the name around and abort
>> the method.
> 
> Wouldn't it be simpler to provide an exern method that unittests could
> call into?
> 
> extern(C) void testName(char[] name);
> 
> unittest
> {
>     testName("blargh");
>     assert(false, "too lazy to write a real unit test...");
> }
> 
> You then provide testName somewhere in your runner program.  If you want
> to compile without the unittest frontend, just create a stub object file
> with this in it:
> 
> extern(C) void testName(char[] name) {}
> 
> Should be a hell of a lot faster than tossing exceptions willy-nilly.
> 
> 	-- Daniel

There are advantages to throwing an exception when registering the name:

unittest {
    testName("this is the test that doesn't end");
    while (true) {}
}

I was thinking that AssertionErrors couldn't be caught, but that was an 
error on my part.



More information about the Digitalmars-d mailing list