DUnit

D is an innovative language in that it incorporates unittests into the language rather than leaving them in the standard library. There are a few problems with D's implementation, though:

  • Unittests are not named. When a test fails, the only information you get is the name of the exception thrown. This is exacerbated by the arbitrary order in which they are executed.
  • As soon as one test fails, the application aborts. Again, due to the arbitrary and unknown order, this is a problem; the test might have failed due to a dependency of the test rather than a failure in the code that the test was intended to probe.
  • There is no organization with D unittests. While this allows programmers to organize their tests in any way they desire, it also means they are free not to organize them, requiring additional effort to avoid code duplication and find failing tests.

An xUnit library solution takes care of these issues. DUnit is the first such implementation for D.

Additionally, as typical of xUnits, an assertions framework is also provided as part of DUnit.

Downloads

Get them on the Downloads page.

Running tests

With DUnit 0.1, you can simply compile with -unittest like normal unittests. In the future, I'll be making more featureful unittest runners, for the console and eventually a graphical one. In addition, integration with CruiseControl and Descent will be of high priority.

Examples

The following sample is taken from the tests for DUnit:

import dunit.api;

class TestTest : TestFixture
{
    mixin(DunitTest); // to execute automatically when unittests are running
    public
    {
        int setupcount;
        int teardowncount;
        int test_one_count;
        int test_two_count;

        // This is run before every test
        override void setup ()
        {
            setupcount++;
        }

        // This is run after every test, assuming that the test
        // has not thrown an exception so far
        override void teardown ()
        {
            teardowncount++;
        }

        this ()
        {
            // Here we define our tests.
            // This first test fails, so teardown isn't executed after it.
            // The error message is printed to stdout, and the tests continue.
            tests["test one"] = 
            {
                test_one_count++;
                assert(false, "this is an expected error");
            };
            
            // This test passes, so teardown is executed afterward.
            tests["test two"] =
            {
                test_two_count++;
            };
        }
    }
}