I am developing a test-framework. There are a number of test-suites, each is a class with a set of member functions for each individual test.
I would like to find a way to dynamically iterate through all of the tests in a class.
The idealised setup might look something like this:
class A : public Test
{
public:
A() {
addTest(a);
addTest(b);
addTest(c);
}
void a() { cout << "A::a" << endl; }
void b() { cout << "A::b" << endl; }
void c() { cout << "A::c" << endl; }
};
The addTest() method will add its parameter to a list; this list is iterated through at a later point and each method is run.
Is there any way to achieve this? The closest we have come up with so far is this:
class Test
{
public:
template <typename T>
struct UnitTest
{
typedef void (T::*P)();
P f;
UnitTest(P p) : f(p) {}
};
// (this struct simplified: we also include a name and description)
virtual void run(int testId) = 0;
};
class A : public Test
{
public:
A() {
mTests.push_back(UnitTest<A>(&A::a));
mTests.push_back(UnitTest<A>(&A::b));
mTests.push_back(UnitTest<A>(&A::c));
}
void a() { cout << "a" << endl; }
void b() { cout << "b" << endl; }
void c() { cout << "c" << endl; }
// not ideal - this code has to be repeated in every test-suite
void run(int testId)
{
(this->*(mTests[testId].f))();
}
vector<UnitTest<A>> mTests;
};
To invoke one test per-iteration of the main run-loop:
a->run(mTestId++);
This is not ideal because every test-suite (class) has to repeat the run() code and have its own mTests member.
Is there a way to get closer to the ideal?
Make each test a functor or function object. Create a container of pointers to the tests and then iterate over the container:
This is the foundation. I am currently using this pattern but have expanded to include a Resume() method and status reporting.