SourceForge.net Logo

[SourceForge Project page] [DUT home] [Why Use DUT] [Plans for DUT] [DUT with multiple threads]


Getting DUT

DUT is hosted on sourceforge. Vist the at project page from which you can get the latest release.

Browsing the SVN archive lets you see the code without grabbing the tarbal. But there's more! The archive contains some sample code that is not included in the releases. You can checkout the code from the repository with:

svn co http://dut.svn.sourceforge.net/svnroot/dut dut

Installing the code

The working part of DUT is two files: dut.make and dut.h. These should be installed (with LICENSE.GPL) in a single directory somewhere on your system.

The fastest thing to do is

cd /your/code/directory; tar xzf /download/directory/dut.tgz
which will create in /your/code/directory a directory called dut_tests containing all the needed files, and dut.template.

Alternately you can install the needed files anywhere on your system. Perhaps /usr/local/include/dut or $(HOME)/include/dut

Configuring your makefile

At a bare minimum, you'll need to tell your makefile where to find the elements of DUT, and include the makefile fragment. Something like this:

DUT_DIR=/path/to/your/dut/instalation 
include $(DUT_DIR)/dut.make
Then when you run make dut_test, make will look in the directory specified by $(DUT_TESTS_DIR) for find test code to compile, then run.

Of course, you probably want to link your test cases against your code. So set DUT_OBJS (and perhaps DUT_LD_FLAGS and/or DUT_LD_LIBS if you need to specify any linking details or additional libraries). You may also need to set the compiler flags (DUT_CC_FLAGS), and the source and object suffixes for the test code (DUT_SRC_SUF, and DUT_OBJ_SUF).

Various other make variables are available to control the compilation behavior of DUT. See README.dut.

Writing test cases

The file dut.template in the distribution is the place to start, clone it, rename the clone with a source code suffix, and start coding. All the test cases should go after DUT_FILE_HEADER and before DUT_FILE_FOOTER.

You have a number test of macros at your disposal (the _WARN variants print a message to the user, but do not stop execution) are:

DUT_PASS[_WARN](DESC)
DUT_FAIL[_WARN](DESC)
These are used to test paths through branching structures that are not conveniently expressed as a Boolean assertion. Each of these increment the test number by one, so the user should insure that one (and only one) is executed on each path, or the test count may be off at the end of the file.
DUT_TESTEQ[_WARN](DESC, CVAL, TVAL, PFMT, CVAR)
DUT_TESTNE[_WARN](DESC, CVAL, TVAL, PFMT, CVAR)
Test the (non-)equality of any objects which can be assigned with the = operator and compared using the == operator.
DUT_TESTEQF[_WARN](DESC, CVAL, TVAL, PFMT, CVAR)
DUT_TESTNEF[_WARN](DESC, CVAL, TVAL, PFMT, CVAR)
As above, but for floating point comparisons for which some granularity (the granularity is given by the global macro DUT_EPSILON which is defined in dut.h as 1e-5. The user is free to redefine it) is acceptable. The actual test for equality is:
CVAR = (CVAL);
if (((0==TVAL)&&(fabs(CVAR)                 > DUT_EPSILON)) ||
                (fabs((TVAL)-(CVAR))/(TVAL) > DUT_EPSILON)) <fail>;
};
The not-equal test has the opposite sense.
DUT_TESTEQS[_WARN](DESC, CVAL, TVAL)
DUT_TESTNES[_WARN](DESC, CVAL, TVAL)
Test the (non-)equality of classical c-strings (char *) using strcmp().
DUT_TESTSIG[_WARN](DESC, CVAL, TVAL)
Test that the code does throw the expected signal
DUT_TESTEXCEPTION[_WARN](DESC, CVAL, TVAL, PFMT)
Test that the code does throw the expected C++ exception
The arguments to these macros are:
DESC
A DESCription of the test being run. This is the biggest part of the feedback you'll get from DUT in the event of a failure, so make it meaningful.
CVAL
The Check VALue. In fact this can be any legal code. It is guaranteed to be evaluated only once (see CVAR, below), so side-effects are permitted.
TVAL
The Test VALue. This may (or may not) be evaluated more than once, so you should definitely not allow any side-effects.
PFMT
A string expressing a printf style output argument appropriate for use with objects of the typeof(CVAL)
CVAR
Cache VARiable. Used to store the results of evaluating CVAL. It should have the same type. A number of built-in variables are present for simple types: and the user may define any other that are needed.

Before version 0.8 (and still available if you define _OLD_DUT_VARS_) we used the now deprecated

  • char ccc;
  • int iii;
  • float fff;
  • double ddd;
  • const void* ppp;
  • const char* sss;

Data type macros

New in version 0.8.2:

The DUT_TEST{EQ,NE} macros have picked up variation which take a data type instead of a caching variable to prevent multiple evaluation of CVAL (and now also of TVAL).

The DUT_TEST{EQF,NEF} macros have picked up variation which assume a data type of DUT_FLOAT_TYPE (which defaults to double) instead of a caching variable to prevent multiple evaluation of CVAL (and now also of TVAL).

The new macros are:

DUT_TESTEQ_TYPE(DESC, CVAL, TVAL, TYPE, PFMT)
DUT_TESTNE_TYPE(DESC, CVAL, TVAL, TYPE, PFMT)
Test the (non-)equality of any objects which can be assigned with the = operator and compared using the == operator.
DUT_TESTEQF_NOCACHE(DESC, CVAL, TVAL, PFMT)
DUT_TESTNEF_NOCACHE(DESC, CVAL, TVAL, PFMT)
As above, but for floating point comparisons for which some granularity (the granularity is given by the global macro DUT_EPSILON which is defined in dut.h as 1e-5. The user is free to redefine it) is acceptable. The not-equal test has the opposite sense.

Organising test cases

Unit testing systems need a mechnism for grouping related tests together, and for insuring that tests are run in sequence, or at least that test order respects a dependecy tree.

DUT achieves these goals by grouping related tests into individual test files, and running the files in a fixed order.

Unfortunatly, the order is the lexical order of their files names. I have established a convention of naming files XXXXX_some_descriptive_stuff.suf, where XXXXX is a five digit string intended solely to force the order in which tests are run.

Compiling and running your test cases

Try make dut_test. If a test case fails, DUT will print a fairly informaitve message and make will halt. At that point it is up to you to go figure out what happened and fix it.

If you're having trouble getting everything to compile, try make dut_info to see how the variables that control DUT are set.