2 Unit Testing in C

C unit testing

The approach to unit testing frameworks used for Check originated with
Smalltalk, which is a late binding object-oriented language supporting
reflection. Writing a framework for C requires solving some special
problems that frameworks for Smalltalk, Java or Python don’t have to
face. In all of those language, the worst that a unit test can do is
fail miserably, throwing an exception of some sort. In C, a unit test
is just as likely to trash its address space as it is to fail to meet
its test requirements, and if the test framework sits in the same
address space, goodbye test framework.

To solve this problem, Check uses the fork() system call to
create a new address space in which to run each unit test, and then
uses message queues to send information on the testing process back to
the test framework. That way, your unit test can do all sorts of
nasty things with pointers, and throw a segmentation fault, and the
test framework will happily note a unit test error, and chug along.

The Check framework is also designed to play happily with common
development environments for C programming. The author designed Check
around Autoconf/Automake (thus the name Check: make check is
the idiom used for testing with Autoconf/Automake). Note however that
Autoconf/Automake are NOT necessary to use Check; any build system
is sufficient. The test failure messages thrown up by Check use the
common idiom of ‘filename:linenumber:message’ used by gcc
and family to report problems in source code. With (X)Emacs, the output
of Check allows one to quickly navigate to the location of the unit test
that failed; presumably that also works in VI and IDEs.

2.1 Other Frameworks for C

The authors know of the following additional unit testing frameworks
for C:

AceUnit

AceUnit (Advanced C and Embedded Unit) bills itself as a comfortable C
code unit test framework. It tries to mimic JUnit 4.x and includes
reflection-like capabilities. AceUnit can be used in resource
constraint environments, e.g. embedded software development, and
importantly it runs fine in environments where you cannot include a
single standard header file and cannot invoke a single standard C
function from the ANSI / ISO C libraries. It also has a Windows port.
It does not use forks to trap signals, although the authors have
expressed interest in adding such a feature. See the
AceUnit homepage.

GNU Autounit

Much along the same lines as Check, including forking to run unit tests
in a separate address space (in fact, the original author of Check
borrowed the idea from GNU Autounit). GNU Autounit
uses GLib extensively, which means that linking and such need special
options, but this may not be a big problem to you, especially if you are
already using GTK or GLib. See the GNU Autounit homepage.

Standard C, with plans for a Win32 GUI implementation. Does not
currently fork or otherwise protect the address space of unit tests.
In early development. See the CUnit homepage.

CuTest

A simple framework with just one .c and one .h file that you drop into
your source tree. See the CuTest homepage.

CppUnit

The premier unit testing framework for C++; you can also use it to test C
code. It is stable, actively developed, and has a GUI interface. The
primary reasons not to use CppUnit for C are first that it is quite
big, and second you have to write your tests in C++, which means you
need a C++ compiler. If these don’t sound like concerns, it is
definitely worth considering, along with other C++ unit testing
frameworks. See the
CppUnit homepage.

embUnit

embUnit (Embedded Unit) is another unit test framework for embedded
systems. This one appears to be superseded by AceUnit.
Embedded Unit homepage.

MinUnit

A minimal set of macros and that’s it! The point is to
show how easy it is to unit test your code. See the
MinUnit homepage.

This list was last updated in March 2008. If you know of other C unit
test frameworks, please send an email plus description to
check-devel AT lists.sourceforge.net and we will add the entry
to this list.

It is the authors’ considered opinion that forking or otherwise
trapping and reporting signals is indispensable for unit testing (but
it probably wouldn’t be hard to add that to frameworks without that
feature). Try ’em all out: adapt this tutorial to use all of the
frameworks above, and use whichever you like. Contribute, spread the
word, and make one a standard. Languages such as Java and Python are
fortunate to have standard unit testing frameworks; it would be desirable
that C have one as well.