One thing I'm pretty doctrinaire about when it comes to this sort of thing is printing out more than just a simple message. Quite often, this makes the problem obvious with no need for deeper investigation. To do this I have a bunch of macros like this: /* check A and B are equal. */ #define EQ_II(A,B,M) (CheckEQII((A),(B),M,#A,#B,__FILE__,__LINE__)) You use it like this: EQ_II(i,3,"blah blah blah"); CheckEQII looks…
You just `assert` an expression, and on failure it'll break down each sub-expression and show whatever it yielded, plus by default it captures all output (stdout and stderr) and prints it out only on failure (so logging and other console output is not painfully annoying while testing) and the fixtures systems is just fantastic and parameterised tests make for much clearer data-driven (/table-driven) tests and the tests selection at the CLI is awesome.
And all the complexity is in the test framework and runner, all you do is write
def test_thing(a_fixture):
assert foo(bar) == a_fixture.some_thing()
or whatever.