Hack to name unit tests?

Daniel Keep daniel.keep.lists at gmail.com
Thu Nov 29 17:35:29 PST 2007



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



More information about the Digitalmars-d mailing list