Professional C__ - Marc Gregoire [446]
Even if you adopt the methodology of writing tests before writing code, you should still run the tests immediately after they are written. This way, you can prove to yourself that the tests fail initially. Once the code is in place, you have tangible data that shows that it accomplished what it was supposed to accomplish.
It’s unlikely that every test you write will have the expected result the first time. In theory, if you are writing tests before writing code, all of your tests should fail. If one passes, either the code magically appeared or there is a problem with a test. If the code is done and tests still fail (some would say that if the tests fail, the code is actually not done), there are two possibilities. The code could be wrong or the test could be wrong.
Unit Testing in Action
Now that you’ve read about unit testing in theory, it’s time to actually write some tests. The following example draws on the object pool example from Chapter 24. As a brief recap, the object pool is a class that can be used to avoid excessive object creation. By keeping track of already created objects, the pool acts as a broker between code that needs a certain type of object and such objects that already exist.
The public interface for the ObjectPool class is as follows. Note that comments have been removed for brevity; consult Chapter 24 for details on the ObjectPool class:
template class ObjectPool { public: ObjectPool(size_t chunkSize = kDefaultChunkSize) throw(std::invalid_argument, std::bad_alloc); shared_ptr void releaseObject(shared_ptr // [Private/Protected methods and data omitted.] }; Code snippet from ObjectPoolTest\ObjectPool.h If the notion of an object pool is new to you, you may wish to peruse Chapter 24 before continuing with this example. Introducing cppunit cppunit is an open-source unit testing framework for C++ that is based on a Java package called junit. The framework is fairly lightweight (in a good way), and it is very easy to get started. The advantage of using a framework such as cppunit is that it allows the developer to focus on writing tests instead of dealing with setting up tests, building logic around tests, and gathering results. cppunit includes a number of helpful utilities for test developers, and automatic output in various formats. The full breadth of features is not covered here. We suggest you read up on cppunit at http://cppunit.sourceforge.net. The most common way of using cppunit is to subclass the CppUnit::TestFixture class (note that CppUnit is the namespace and TestFixture is the class). A fixture is a logical group of tests. A TestFixture subclass can override the setUp() method to perform any tasks that need to happen prior to the tests running, as well as the tearDown() method, which can be used to clean up after the tests have run. A fixture can also maintain state with member variables. A skeleton implementation of ObjectPoolTest, a class for testing the ObjectPool class, is shown here: #include class ObjectPoolTest : public CppUnit::TestFixture { public: void setUp(); void tearDown(); }; Code snippet from ObjectPoolTest\ObjectPoolTest.h Because the tests for ObjectPool are relatively simple and isolated, empty definitions will suffice for setUp() and tearDown(). The beginning stage of the source file is shown here: #include "ObjectPoolTest.h" void ObjectPoolTest::setUp() { } void ObjectPoolTest::tearDown() { } Code snippet from ObjectPoolTest\ObjectPoolTest.cpp That’s all the initial code we need to start developing unit tests. Writing the First Test Since this may be your first exposure to cppunit, or to unit tests at large, the first test will be a very simple one. It tests whether 0 <1. An individual unit test in cppunit is just a method of the fixture class. To create a simple test, add its declaration to the ObjectPoolTest.h