Back when I was working in C++ (disclaimer: this was about 2005), I used a slightly modified version of TUT (Template Unit Test Framework). I liked it because it was so lightweight, which made it easy to modify, and meant there was very little "glue" required when writing tests.
Here is one very simple modification I made, that makes it even eaiser/cleaner to write tests:
static int BogusFunction() { return __COUNTER__; } // Increment the __COUNTER__ to the correct position for the begining of the tests
#define TEST template<> template<> void object::test<__COUNTER__>()
#define ENSURE(msg, cond) ensure(msg, cond, __FILE__, __LINE__)
#define ENSURE_EQUALS(msg, actual, expected) ensure_equals(msg, actual, expected, __FILE__, __LINE__)
#define ENSURE_DISTANCE(msg, actual, expected, distance) ensure_distance(msg, actual, expected, distance, __FILE__, __LINE__)
#define FAIL(msg) fail(msg, __FILE__, __LINE__)
The other change I made was to its output format, so that test failures would appear correctly in Visual Studios's error list (when run as part of a build), clickable to go to the file and line of the failed test.
(The ability to do this sort of thing means that it can be made to fit into your TDD/CI process, rather than forcing you to fit into its.)
Here is an example test (from the command-stack from my editor):
TEST // Undoing a command
{
cs.AddCommand(new TestCommand);
cs.AddCommand(new TestCommand(od));
ENSURE("Undo success", cs.Undo());
ENSURE_EQUALS("Stack size", cs.size(), 2);
ENSURE_EQUALS("Command's Undo() was called", od.undo, 1);
ENSURE_EQUALS("Command's Redo() not called", od.redo, 0);
ACommandStack::const_iterator it = cs.end();
ENSURE("Command is redoable", cs.GetUndoPos() == --it);
}
(In the above code, cs
and od
are per-module fixtures, and TestCommand
is a mock object.)