The basis of testing is very basic. You check that an expected value matches an actual value. For example, in JUnit we might write something like this...
Wibble expected = someExpression;
Wibble actual = someOtherExpression;
assertEquals(expected, actual);
You might not have noticed it before but it's quite likely your test code contains a lot of repeated occurrences of that last line (in whatever form it takes). When something keeps re-occuring you should start to wonder what the missing abstraction is. The names expected and actual are extremely strong stylized hints that an assertEquals is about to happen. And then it does happen! So how about writing something like this instead?
expected = 42;
actual = expression();
and somehow the test framework takes it as read that it has to do an assertEquals. In C++ we can put behaviour in a destructor and create an object in a scope, thus automating the behaviour when the object goes out of scope. Based on this idea I've come up with...
ARE_EQUAL(int)
{
...
expected = 42;
actual = expression();
}
The idea is that ARE_EQUAL is a macro
#define ARE_EQUAL(type) \
if (const wrapper<type> & expected = wrapper<type>()); \
else \
if (const wrapper<type> & actual = wrapper<type>()); \
else \
if (const auto_asserter<type> & rrid = \
auto_asserter<int>(expected,actual)); \
else
which relies on
template<typename type>
struct wrapper
{
operator bool() const { return false; }
const wrapper & operator=(const type & rhs) const
{
value = rhs;
return *this;
}
mutable type value;
};
and
template<typename type>
class auto_asserter
{
public:
auto_asserter(
const wrapper<type> & expected,
const wrapper<type> & actual)
: expected(expected)
, actual(actual)
{
}
~auto_asserter()
{
assert(expected.value == actual.value);
}
operator bool() const { return false; }
private:
const wrapper<type> & expected;
const wrapper<type> & actual;
};