unittests and templates

Steven Schveighoffer schveiguy at yahoo.com
Tue May 11 13:06:31 PDT 2010


A cool thing I learned on the way to d2.

unittests can be templatized just like the classes/structs they reside  
in.  When enhancing dcollections with lots of detailed unit tests, I was  
doing things like this:

class ArrayList(V)
{
    V take() {...}
    unittest
    {
       auto al = new ArrayList!uint;
       al.add([0u, 1, 2, 3, 4]);
       assert(al.take() == 4);
       assert(al.length == 4);
    }
}

But I found that the unittests weren't compiling -- at all!  What I  
realized is that unittests are part of the instantiation!

At first, I was peeved, I wanted to simply test the "take" function not  
caring what type I used to instantiate the class with.  In order to do  
that, I have to move all the unit tests outside the class declaration --  
not good for maintainability.

But I came to realize -- there is great power in that feature.  For  
example, with a little change to my unit test:

unittest
{
    auto al = new ArrayList;
    al.add([cast(V)0, 1, 2, 3, 4]);
    assert(al.take() == 4);
    assert(al.length == 4);
}

I can create a global unit test that looks like this:

unittest
{
   ArrayList!uint al1;
   ArrayList!int al2;
   ArrayList!ulong al3;
   ArrayList!long al4;
}

and now my unit tests cover 4 instantiations.  With a single line, I can  
extend my unittest coverage to another type!

Of course, the issue is, how do I write a truly generic unit test?  For  
example, that 'take' unit test fails for ArrayList!string.  If I wanted to  
compile a project that happened to include the string instantiation with  
unit tests turned on, it fails to compile.

The ugly solution is to use static if like so:

static if(isIntegral!V)
{
    unittest
    {
    }
}

But that is, well, ugly.  I thought of proposing something like:

unittest if(isIntegral!V)
{
}

which looks better, but still is a bit verbose.  This might be the  
cleanest solution.  Any suggestions?

I still would like a way to do a unittest inside a template that is  
technically not part of the instantiation.  This allows you to unit test a  
function with a specific instantiation when it's not easy to build a  
generic unit test *and* you want the unit test close to the function  
declaration.  Although it's bloaty, you could just write your unittests  
like I did originally, specifying the full type in the unit test, but you  
then have to remember to create an external unit test to do the  
instantiation.

I hate to suggest static unittest :P  Any other ideas?

-Steve


More information about the Digitalmars-d-learn mailing list