Instance-specific unittests

Steven Schveighoffer schveiguy at yahoo.com
Mon Feb 13 16:15:18 PST 2012


On Mon, 13 Feb 2012 18:12:15 -0500, H. S. Teoh <hsteoh at quickfur.ath.cx>  
wrote:

> I discovered something really cool today, and I thought I'd share it
> with my fellow learners:
>
> The unittest block is used for inserting unit tests that are executed at
> runtime before main() is called. They are very useful for inserting
> little tests after a piece of complex code, to make sure it actually
> works as expected.
>
> What's cool is that if you have a unittest block inside a class or
> struct with compile-time parameters:
>
> 	struct S(bool B) {
> 		void method() { ... }
> 		unittest {
> 			/* test method() for correct operation */
> 		}
> 	}
>
> then the unittest will be executed once *per instance* of S.

[snip]

As Jonathan suggests, it's once per instantiation, though I think that's  
what you meant.

Dcollections has been doing this ever since the D2 branch was introduced  
(circa May 2010).  I use the following idiom to great success:

class SomeClass(T)
{
    enum doUnitTests = isIntegral!T;

    static if(doUnitTests) unittest {
      ... // unit test using the assumption that T is integral type.
    }
}

// at bottom of file:
unittest
{
    SomeClass!int intv; // run int unit tests
    SomeClass!uint uintv; // run uint unit tests
    ...
}

One other really nice benefit is that you don't have to specify template  
parameters, just use the class identifier inside the unit test.

I have found the following issues with doing stuff this way:

1. The more values of T you try to test for, the more difficult it becomes  
to make a "generalized" unit test.  But for the most part, I've found that  
for integral types, you can do a lot with integer literals.  Making helper  
functions that construct your object using the same literal parameters  
helps immensely.
2. It's not enough to just rely on your global unit test to instantiate  
just the right ones -- because a template can be instantiated by a user of  
your lib while in unit test mode, you never know in what mode your  
template will be instantiated.
3. If you are making classes like this, make *sure* all your unit test  
helper functions are non-virtual!  Otherwise, if some code instantiates  
with unit tests on and some off, you will have vtable inconsistencies.

I'd link to example source on dcollections, but dsource appears to be down  
(github here I come!)

-Steve


More information about the Digitalmars-d-learn mailing list