Quick Test-First Sample in C++

by C. Keith Ray Copyright (C) 2002 by C. Keith Ray; All rights reserved.

This document may be found at < http://homepage.mac.com/keithray/QuickCppTestFirst.html >

While uncommon, test-first programming has several advantages over no-testing or test-last-programming, including encouraging you to write the simplest class necessary (but not too simple), and being easier psychologically to test code you have written yet -- in test-last, you just don't WANT to find bugs in code you just wrote, while writing a test for a piece of code you haven't yet written doesn't have that mental block against it.

There are several C and C++ unit-test frameworks here: < http://www.xprogramming.com/software.htm >

The secret is to never write a piece of production code without needing it to exist in order to pass a test.

In order to be able to test an individual class in isolation, you will occasionally need to use a 'stub' or 'mock object' so that you can simulate external error conditions or avoid slow real-world interactions. This encourages you to write interfaces or abstract base classes, so your mock object in the test can replace a real object. Avoiding dependance of concrete classes on other concrete classes is a good thing.

A book on test-driven-development is in progress here: < http://groups.yahoo.com/group/testdrivendevelopment/ >

See <http://www.refactoring.com > and the book "Refactoring: Improving the Design of Existing Code " by Martin Fowler; ISBN 0-201-48567-2

By refactoring to remove duplication and to make expressing intentions clearer, you will evolve only the minimum number of classes needed by your application.

I will try to show how I'd evolve some classes from being “too simple” to being functional...

First, what do I want to do? I have a vague requirement for a scheduler and a unit. Let's say the scheduler is given one or more 'units' of work, and runs them when asked to.

void TestSchedulerOneUnit()
{
   Scheduler  sched;
   Unit work;
   sched.Accept( &work );
   sched.Run();
// now how do we know it was executed? Let's ask work.
   assertEquals( true, work.wasRun );
}

Now we have to implement just enough to make this compile and run...

  class Unit
  {
  public:
     bool wasRun;

     Unit()
       : wasRun( false )
     {
     }

     virtual ~Unit()
     {}
  };

  class Scheduler
  {
  public:
     virtual void Accept( Unit* aUnit )
     {
     }

     virtual void Run()
     {
     }

     virtual ~Scheduler()
     {}
  };

Before anyone starts jumping up and down yelling about public member variables and empty methods, please understand that this code will evolve, but first we want the test to compile and fail, so we're sure the test is being executed. The we'll write code to make the test pass, and we'll know from the success of the test we wrote the right code.

My C++ test framework requres something more complicated than that above, but let's avoid getting mired into too many details.

We compile and run, and our output is something like

failed: expected 'true' but was 'false' at line 8 of “Test”

I decide that Unit has a Run method to be called by Scheduler, and so...

   class Unit
   {
   public:
      bool wasRun;

      Unit()
        : wasRun( false )
      {
      }

      virtual ~Unit()
      {}

      virtual void Run()
      {
         wasRun = true;
      }
   };

   class Scheduler
   {
      Unit* mUnitToRun;
   public:
      Scheduler()
        : mUnitToRun( 0 )
      {
      }

      virtual ~Scheduler()
      {}

      virtual void Accept( Unit* aUnit )
      {
         mUnitToRun = aUnit;
      }

      virtual void Run()
      {
         mUnitToRun->Run();
      }
   };

Now the test passes. The next thing I think of, is what if there is nothing to run? So I write a test for that...

   void TestSchedulerNothing()
   {
      Scheduler  sched;
      sched.Run();
   // now how do we know it was executed? We know because 
   // it doesn't crash... maybe there is a better way, but I'm 
   // winging it.
   }

   class Scheduler
   {
      Unit* mUnitToRun;
   public:
      Scheduler()
        : mUnitToRun( 0 )
      {
      }

      virtual ~Scheduler()
      {}

      virtual void Accept( Unit* aUnit )
      {
         mUnitToRun = aUnit;
      }

      virtual void Run()
      {
         if ( mUnitToRun != 0 )
         {
            mUnitToRun->Run();
         }
      }
   };

What else? Multiple units to run...

   void TestSchedulerTwoUnits()
   {
      Scheduler  sched;
      Unit work1;
      Unit work2);
      sched.Accept( &work1 );
      sched.Accept( &work2 );
      sched.Run();
   // now how do we know it was executed? Let's ask work1 and work2.
      assertEquals( true, work1.wasRun );
      assertEquals( true, work2.wasRun );
   }
This test fails, indicating tht work1.wasRun is false... so we write code to make it pass (and keeping the previous tests passing.)
   class Scheduler
   {
      std::vector<Unit*> mUnitsToRun; // maybe 'list' instead?
   public:
      Scheduler()
      {
      }

      virtual ~Scheduler()
      {}

      virtual void Accept( Unit* aUnit )
      {
         mUnitsToRun.push_back( aUnit );
      }

      virtual void Run()
      {
         for ( int i = 0; i < mUnitsToRun.size(); i++ )
         {
            mUnitToRun[ i ]->Run();
         } // should use iterator, but I didn't want to look up 
           // the syntax.
      }
   };

Now all the tests are passing.

Up to now, I could keep everything in one .cpp file, but I think it's getting too large, so I create .h and .cpp files, putting declarations only in the .h files, and implementations in the .cpp files... I also realize that the implementation of Unit for these tests is not what I want for the 'real' unit, so I change Unit to an abstract base class, and subclass Unit in my test code...

   // Scheduler.h -----------------------

   class UnitInterface;

   class Scheduler
   {
      std::vector<UnitInterface*> mUnitsToRun; // maybe 'list' instead?
   public:
      Scheduler();

      virtual ~Scheduler();

      virtual void Accept( UnitInterface* aUnit );

      virtual void Run();
   };

   // Scheduler.cpp -----------------------

   #include "Scheduler.h"
   #include "UnitInterface.h"

   Scheduler::Scheduler()
   {
   }

   Scheduler::~Scheduler()
   {
   }

   void Scheduler::Accept( Unit* aUnit )
   {
      mUnitsToRun.push_back( aUnit );
   }

   void Scheduler::Run()
   {
       for ( int i = 0; i < mUnitsToRun.size(); i++ )
       {
          mUnitToRun[ i ]->Run();
       } // should use iterator
   }

   // UnitInterface.h ----------------

   class UnitInterface
   {
   public:
      virtual ~UnitInterface();

      virtual void Run() = 0;
   };

   // UnitInterface.cpp

   UnitInterface::~UnitInterface()
   {
   }

   // SchedulerTest.cpp ------------

   #include "UnitInterface.h"
   #include "Scheduler.h"

   class MockUnit : public UnitInterface
   {
   public:
      bool wasRun;

      MockUnit()
        : wasRun( false )
      {}

      virtual void Run()
      {
         wasRun = true;
      }
   }

   void TestSchedulerOneUnit()
   {
      Scheduler  sched;
      MockUnit work;
      sched.Accept( &work );
      sched.Run();
   // now how do we know it was executed? Let's ask work.
      assertEquals( true, work.wasRun );
   }

   void TestSchedulerNothing()
   {
      Scheduler  sched;
      sched.Run();
   // now how do we know it was executed? We know because 
   // it doesn't crash... maybe there is a better way, but I'm 
   // winging it.
   }

   void TestSchedulerTwoUnits()
   {
      Scheduler  sched;
      Unit work1;
      Unit work2);
      sched.Accept( &work1 );
      sched.Accept( &work2 );
      sched.Run();
   // now how do we know it was executed? Let's ask work1 and work2.
      assertEquals( true, work1.wasRun );
      assertEquals( true, work2.wasRun );
   }

Now, I could start writing tests on UnitInterface, or on NamedUnit (a subclass of UnitInterface), to add names and whatever other functionality I want Unit to have, either adding the name field and methods to the base class, or to a subclass, depending on whether I would ever want a subclass of Unit that doesn't have names.

I retain the Scheduler tests and the Unit tests to serve as regression test throughout the project, and never check code into source code control unless all the unit tests are passing.

You may notice there are no private or protected functions in the code above. Whenever possible, I want the functions visible so I can test them, and any function that I would want to make private 'for safety', I would instead push that function into another class, and use an instance of that new class as a private member.

I would also add tests to Scheduler or some other class, to insure there are no memory leaks, which may require modifying Scheduler and its tests, or some other class and its tests.