test-o-matic 0.4.1
test-o-matic is copyright (c) Edd Dawson 2011

test-o-matic is a unit testing library for C++. It is not a framework; it is
designed to let each person write and organize tests in their own way.


  * free for use in commercial, closed-source and open-source software
  * small (approx. 500 lines of code in 1 source file and 1 header file)
  * quick and easy to use
  * quick and easy to build
  * quick and easy to modify
  * portable
  * flexible and extensible
  * unintrusive
  * independent of any 3rd party code

Below you will find all that's needed to get started with test-o-matic. For
information and examples relating to customizing and adapting the library
further, please visit the Cookbook at

Writing tests
If tests are hard to write, they don't get written. So test-o-matic minimizes
boilerplate code as far as possible.

For extremely quick-and-dirty tests, you can use the macros provided by
test-o-matic in your main() function:

  #include <test_o_matic.hpp>

  int main()
      CHECK(1 == 1);
      THROWS(throw std::runtime_error("oops"), std::exception);
      // ...

      // To print a summary:
      return get_local_tom_logger().summary(std::cout);

However, as the number of tests grows, this approach soon becomes unwieldy.
It's best to try to keep tests isolated so that they don't step on each other's

Here's the code needed for an isolated test, assuming we're testing a bignum

  TEST("bignum equality")
      bignum one(1), three(3), five(5);
      CHECK(five == five);
      CHECK(!(one == three));

This defines a test with the name "bignum equality". The CHECK() macro tests
that the expression given as an argument evaluates to true.

There is also a REQUIRE() macro, that is like CHECK() but will abort the test
if it fails; CHECK() will proceed to the next statement in the code regardless
of whether it passed or failed.

The ABORT() macro can be called at any time to quit a test. You can also simply
use a return statement, but that won't generate any output.

The TRY() macro checks that an expression doesn't throw an exception.

  TEST("bignum construction")

The THROWS() macro checks to see if an expression throws a particular type of
exception. Here we check that division by zero throws a divide_by_zero object.

  TEST("bignum division")
      THROWS(bignum(1) / bignum(0), divide_by_zero);

I've found that these macros cover all the cases I've ever been interested in,
but it is also easy to write your own macros to deliver arbitrary messages to
the logging system.

Writing fixtures
Sometimes you may find that you end up writing a lot of initialization code
that is repeated among tests. This can be mitigated by writing what's known as
a fixture.

In test-o-matic, a fixture is simply a class or struct with a public zero-
argument constructor. If we find that we're creating lots of bignum tests that
use objects called zero, one and huge, we could do this to save some

  struct common_bignums
      bignum zero;
      bignum one;
      bignum huge;

      my_fixture() : zero(0), one(1), huge("9999999999999999999999") { }

      // you can add a destructor too, if you need to tear down anything

  TESTFIX("bignum multiplication", common_bignums)
      // The member variables of a fixture are made available to the test:
      CHECK(one * one == one);
      CHECK(zero * one == zero);
      TRY(huge * huge);

Such a fixture class can be used in any number of tests. Note that we used the
TESTFIX() macro here, rather than TEST().

Running your tests
Here's how to run all the tests we just created:

  namespace tom { using namespace test_o_matic; }

  int main()
      const bool verbose = true;
      tom::simple_logger lgr(std::cout, verbose);
      tom::runner rnr;

      for (const tom::test *t = tom::first_test(); t; t = t->next)
          tom::run_test(*t, lgr, rnr);

      return lgr.summary(std::cout);

Note how it's possible to iterate over all the tests. Each test object has a
bunch of fields:

  * name - the name of the test e.g. "bignum construction"
  * file - the name of the C++ source file in which the test is defined
  * line - the line number at which the test definition starts
  * date - the date on which the test was compiled e.g. "Apr 15 1982"
  * time - the time at which the test was compiled e.g. "16:30:10"
  * next - a pointer to the next test

You can use this information to filter out the tests you're not interested in,
or collect tests in to suites of some kind. Perhaps you only want to run all
tests that were compiled today, or within the last 10 minutes?

A logger object is used to print information about events and gather basic
statistics as tests run. A runner object is used to call each test. Both are
entirely customizable.

Organising your tests
There are no restrictions on where you should put your tests. I tend to collect
the tests for a given component in to a file and put the test-execution loop in
its own file, too.

timer_tests.cpp // tests for timer
animator_tests.cpp // tests for animator
interpolator_tests.cpp // tests for interpolator
run.cpp // code to run the tests

But for a quick fix you can put the test definitions and running code all in a
single file.

Another interesting strategy is to have all tests for a given class in their
own file as before, but now compile them in to a shared libraries
(.dll/.so/.dylib). Each shared library will export the first_test() and
run_test() functions, allowing you to dynamically load and run tests using
functions such as

  * LoadLibrary/GetProcAddress on Windows
  * dlopen/dlsym on UNIX and Mac

So rather than having lots of little test applications, you instead have lots
of little test libraries and a single program to run them. Perhaps the program
can descend a directory hierarchy looking for tests and/or test libraries that
match a user-specified pattern?

Such a program isn't provided by test-o-matic as I'd like to keep the library
super-lean. Perhaps I'll start another project at some point to provide a
library or program for this purpose...

More information
For more information on test-o-matic please visit:

  * (includes a wiki)
  * (the author's website)

Thanks for trying test-o-matic.

  -- Edd