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.
|
|