The abstract Test base class declares a pure virtual run method:
class
Test
{
public:
virtual bool run() = 0;
};
The TestSuite class manages a list of tests:
class TestSuite : public Test
{
public:
void add(Test* test)
{
children.push_back(test);
}
virtual bool run();
private:
list<Test*> children;
};
The run method calls the run method of each child until one fails or until all pass:
bool TestSuite::run()
{
bool result = true;
list<Test*>::iterator p;
for(p = children.begin(); p != children.end() && result; p++)
{
result = result && (*p)->run();
}
return result;
}
The TestCase template holds a subject function and an oracle. It provides a method for adding rows to the oracle as well as a run method. The run method iterates through the oracle, applying the subject to each key and comparing the expected output with the actual output:
template <typename Input, typename Output>
class TestCase : public Test
{
public:
TestCase(Output (*subject)(Input)) { this->subject = subject; }
void setFun(Output (*subject)(Input)) { this->subject =
subject; }
void add(Input input, Output output) { oracle[input] = output; }
bool run()
{
bool pass = true;
map<Input, Output>::iterator p;
for(p = oracle.begin(); pass && (p !=
oracle.end()); p++)
{
pass = pass &&
(p->second == subject(p->first));
}
return pass;
}
private:
Output (*subject)(Input); // pluggable adapter
map<Input, Output> oracle;
};
Assume a library of mathematical functions has been created:
int fact(int n)
{
int result = 1;
for(int i = 1; i <= n; i++) result *= i;
return result;
}
int tri(int n)
{
int result = 0;
for(int i = 1; i <= n; i++) result += i;
return result;
}
// etc.
The programmer must create test cases and test suites by writing code:
int main()
{
TestSuite suite;
TestCase<int, int> aCase = TestCase<int,
int>(&tri);
aCase.add(3, 6);
aCase.add(4, 10);
aCase.add(5, 15);
suite.add(&aCase);
TestCase<int, int> bCase = TestCase<int,
int>(&fact);
bCase.add(3, 6);
bCase.add(4, 24);
bCase.add(5, 120);
suite.add(&bCase);
cout << "pass? = " << suite.run() <<
"\n";
return 0;
}