Unit Testing is always being an essential part of development process. In C++, the smallest unit refers to class which can be considered for writing unit tests. Writing class unit test is a challenge for a well designed class. The well designed class provides abstraction that includes hidden implementation details. Such objects of class is difficult to unit test thoroughly.
Test Class in Isolation – Maintaining Sequence
Testing strategy to test C++ code should be flexible. The aim of the
testing strategy is to prepare guidelines and not rules.
A C++ class contains both member functions and data. Private classes are
are not visible to external program units. Most of the time, internal coupling is
found in the code.
It is recommended to plan unit testing to test the most abstract classes first
then, progress through hierarchy making sure that each new class tested require
classes that have been already unit tested. No need to simulate external
program units, in this case. This unit testing is the right approach for small
application. It is more appropriate in theory.
Test Class in Isolation – Using Stubs Library
Internal coupling in code can be found by virtue of inheritance, containment or as a result of a global object used in a member function. Under such scenario, test must be simulated.
It is recommended to create and maintain a a suite of stub classes alongside their real implementations. A stub can be specified for each of the member functions. These member functions to be simulated from a test script. The stubs are specified for determining that the member function has been called at an expected point, enabling parameters to the member function to be checked against expected values and returning values required by each test case.
A suite of class stubs is referred to as ‘stubs library’.
There is a process to use stubs for unit testing. A developer needs to copy class stubs for each class requiring simulation before testing. Many classes will require simulation and the test stubs file will consequently be large for a highly derived class.
A developer is the best judge to decide on using simulation based testing as he is well aware of the code design and can decide on which test strategy to follow.
Unit Test Maintenance
Unit testing is not one-time task. As the process is part of development, each time the code is modified, altered or used in a new environment, the unit test needs to be repeated. The unit tests should be maintained throughout development life cycle.
There is a cost involved in the unit test maintenance. If an interface to a class is changed in C++ software, then all tests on classes that require the modified class must be repeated.
The need to change interfaces will be bare minimum if a good design. The good design enforces the maximum amount of encapsulation, limiting the externally visible members of a class to a minimum.
Heap leakage refers to memory is allocated for use, but not released when it no longer is required. Good design should protect against heap leakage. Unit testing can be performed to reinforce the heap leakage.
The unit test for a class should ensure that no heap space remains allocated at the end of each test.
Unit testing is done in isolation into bits and pieces. Testing at higher than units also needs to be performed. The testing proving the relationships between objects and overall system functionality is needed.
A gradual approach can be taken to perform integration testing. This is more practical in complex system software. An initial integration build may cover a few fully tested class categories, with the rest of the system being simulated. Then, functional tests on this can be performed and problems are sorted out. Integration gradually progresses with subsequent builds replacing more and more of the simulated classes with their real implementations.
For C++ programs and systems, the natural unit for testing is the ‘class’.