Extending Unit Tests

From D Wiki
Jump to: navigation, search

D's built in unit testing support makes it very convenient to add tests for code right next to that code. This makes for an effective management tool to ensure that unit testing gets done and updated in parallel with the code. In the most straightforward usage of unit testing in D, assert() is used for contract testing:

unittest
{
    assert(x == 5);
}

and if the assert fails, it throws an AssertError exception, which gets caught by the runtime library, a message is printed, and it exits. While this gets the essential job done, some programmers want more flexibility. For example, they'd like it to not stop on the first error, but to collect and log all the errors in one run.

Here are some approaches for doing this:


  • Instead of using:
    assert(e);

in the unit tests, write:

    myassert(e, "message");

and write the myassert() to log any errors to the suitable log file.


  • Provide a custom implementation of:
    extern (C) void _d_assert(char[] filename, uint line);

to do the logging. _d_assert is the function called when an assert trips. By providing your own, it prevents the Phobos library version from being linked in.


  • Catch any AssertError exceptions, log them, and proceed with the unit tests:
import std.asserterror;

unittest
{
    try
    {
        assert(...);
        ...
    }
    catch (std.asserterror.AssertError ae)
    {
    ae.print();
    }
}


With this technique you can control which groups of asserts get skipped if one trips. The point to remember is that the compiler and language doesn't care what code is between the { } of the unittest blocks. It can be any valid D code that does whatever needs to be done.

This article was originally published at http://wiki.dlang.org/Extending_Unit_Tests