Implementing TestIt in C++

Using Function Pointers

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;
};

Testing TestIt

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;
}