Suggestion (ping Walter): Improve unit testing.
Gregor Richards
Richards at codu.org
Sat Apr 21 00:18:49 PDT 2007
There are a number of improvements I'd like to see in D's unit testing
framework. All of them are standard library changes, and I've made them
work in Tango (as an external patch). If they were added to both Phobos
and Tango, DSSS could easily run unit tests, which would improve its
test suite.
Here are two major problems I see with unit tests right now:
1) You can't run only unit tests, you are forced to run main() as well.
2) Unit testing doesn't actually output anything useful, it just works
under the no-news-is-good-news principle.
Each problem has a fairly easy solution in the core library:
1) Adding a special option, handled by the core library's main function,
which will cause only unit tests to run. The changes I made in Tango:
Index: lib/compiler/gdc/dgccmain2.d
===================================================================
--- lib/compiler/gdc/dgccmain2.d (revision 2100)
+++ lib/compiler/gdc/dgccmain2.d (working copy)
@@ -35,7 +35,7 @@
extern (C) void _minit();
extern (C) void _moduleCtor();
extern (C) void _moduleDtor();
-extern (C) void _moduleUnitTests();
+extern (C) void _moduleUnitTests(int);
/***********************************
* These functions must be defined for any D program linked
@@ -108,6 +108,7 @@
{
char[][] args;
int result;
+ int testOnly = 0;
version (GC_Use_Stack_Guess)
{
@@ -137,11 +138,17 @@
}
args = am[0 .. argc];
}
+
+ // check for --d-unittests-only
+ foreach (arg; args) {
+ if (arg == "--d-unittests-only")
+ testOnly = 1;
+ }
void run()
{
_moduleCtor();
- _moduleUnitTests();
+ _moduleUnitTests(testOnly);
result = main_func(args);
isHalting = true;
_moduleDtor();
As you can see, if --d-unittests-only is supplied, it passes a 1 into
the (now modified) _moduleUnitTests function, which will cause it to
exit when finished testing.
2) The _moduleUnitTests function can be improved to provide useful
output. The output I've implemented for Tango is:
Failure in test for module 'test':
tango.core.Exception.AssertException on test.d(7): Assertion failure
TESTS: 1 PASSED: 0 FAILED: 1
The patch to make this work was fairly simple as well:
Index: lib/compiler/gdc/genobj.d
===================================================================
--- lib/compiler/gdc/genobj.d (revision 2100)
+++ lib/compiler/gdc/genobj.d (working copy)
@@ -42,7 +42,8 @@
import tango.stdc.string; // : memcmp, memcpy;
import tango.stdc.stdlib; // : calloc, realloc, free;
import util.string;
- debug(PRINTF) import tango.stdc.stdio; // : printf;
+ //debug(PRINTF) import tango.stdc.stdio; // : printf;
+ extern (C) int printf(char*, ...);
extern (C) void onOutOfMemoryError();
extern (C) Object _d_newclass(ClassInfo ci);
@@ -1054,11 +1055,13 @@
}
/**
- * Run unit tests.
+ * Run unit tests. If testOnly is true, output results and quit.
*/
-extern (C) void _moduleUnitTests()
+extern (C) void _moduleUnitTests(int testOnly)
{
+ int testCount, testFail;
+ testCount = testFail = 0;
debug(PRINTF) printf("_moduleUnitTests()\n");
for (uint i = 0; i < _moduleinfo_array.length; i++)
{
@@ -1070,9 +1073,26 @@
debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
if (m.unitTest)
{
- (*m.unitTest)();
+ testCount++;
+ try {
+ (*m.unitTest)();
+ } catch (Exception e) {
+ printf("Failure in test for module '%.*s':\n", m.name);
+ printf(" %.*s on %.*s(%d): %.*s\n",
+ e.classinfo.name, e.file, e.line, e.msg);
+ testFail++;
+ }
}
}
+ if (testOnly != 0 || testFail > 0)
+ {
+ printf("TESTS: %d PASSED: %d FAILED: %d\n",
+ testCount, testCount - testFail, testFail);
+ if (testFail == 0)
+ exit(0);
+ else
+ exit(1);
+ }
}
These additions are fairly minor, and would make unit testing
immeasurably better than it is right now. The sections I modified in
Tango are mostly the same as the Phobos versions, so the patch should be
almost exactly the same as mine above.
Comments?
- Gregor Richards
More information about the Digitalmars-d
mailing list