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