Testing C

This post is a mirror of https://text.causal.agency/005-testing-c.txt.

This is a simple approach to unit testing in C that I’ve used in a couple projects. At the bottom of a C file with some code I want to test, I add:

#ifdef TEST
#include <assert.h>

int main(void) {
	assert(...);
	assert(...);
}

#endif

This file normally produces a .o to be linked into the main binary. For testing, I produce separate binaries and run them with make(1):

TESTS = foo.t bar.t

.SUFFIXES: .t

.c.t:
	$(CC) $(CFLAGS) -DTEST $(LDFLAGS) $< $(LDLIBS) -o $@

test: $(TESTS)
	set -e; $(TESTS:%=./%;)

Note that the test binaries aren’t linked with the rest of the code, so there is potential for simple stubbing or mocking.

To get the best output from C’s simple assert(3), it’s best to assert the result of a helper function which takes the expected output and the test input, rather than calling assert(3) inside the helper function. This way, the message printed by the assert failure contains a useful line number and the expected output rather than just variable names.

For a real example, check term.c from my IRC client project.