Crash Course in using CppUnit

Introduction

This document will introduce you to a testing framework called CppUnit. CppUnit is a C++ port of the JUnit testing framework developed by Erich Gamma and Kent Beck. It is ported by Michael Feathers. The main purpose of CppUnit is to support developers in doing their unit testing of C++ programs. For students using the C++ language for the project, we expect you to use CppUnit extensively for your testing purposes. Recall that one of the required program quality attributes for your project is reliability. CppUnit can be used to help you achieve that.

This document can be considered a "port" of the JUnit Guide I wrote. In particular, this document talks about using CppUnit in MS Visual C++ 6.0. As in the JUnit Guide, I have included only the bare minimum to get you started. I will first go through the installation of CppUnit in the next section, followed by a description of how to use CppUnit using a sample program. Next, I will suggest some ways of organizing your project and test codes before ending the document with pointers to some useful references.


Installing CppUnit

Installation of CppUnit can be broken down into the following steps:
  1. Download CppUnit and unzip the archive into a location of your choice. For the rest of this document, I will assume that you have unzipped your archive to the directory C:\ and hence the source files are located in C:\CppUnit.
  2. Test your installation to ensure that CppUnit is working:
    1. Start the Visual C++ IDE. Select File->Open. Change the "Files of type" to "Workspaces". Go to C:\CppUnit\ms\culib directory and open the workspace culib.dsw.

      opening a workspace

      Next, select Build->Rebuild All to create the culib.lib library.

    2. Select File->Open again and go to C:\CppUnit\ms\TestRunner directory to open the workspace TestRunner.dsw. Similarly, select Build->Rebuild All to create TestRunner.dll.
    3. Select File->Open and go to C:\CppUnit\ms\HostApp directory to open the workspace HostApp.dsw. After this, select Build->Rebuild All to compile the application. Run the application by selecting Build->Execute HostApp.exe. The TestRunner gui will appear. Just click on the Run button to run the tests.

      Running the tests

      There will be some failures and errors - it's okie. Close the TestRunner window. Another window will pop up. Just close it. CppUnit is now installed properly.

  3. As it is quite complicated to incorporate the graphical interface into the test programs you write, I will only illustrate how to use the text-based interface of CppUnit. Email me if you are interested in running the graphical version. Now, you need to re-compile the CppUnit library for using the text-based interface. First, select File->Open and go to C:\CppUnit\ms\culib to open the workspace culib.dsw again. Next, select Project->Settings. A new dialog will appear. Under the heading "Microsoft Foundation Classes", instead of "Use MFC in a Shared DLL", choose "Not Using MFC".

    changing settings

    Next, add the files for running the text interface. Select Project->Add To Project->Files and go to the directory C:\CppUnit\test\textui and add the files TextTestResult.h and TextTestResult.cpp. You need to change one more setting. Select Project->Settings and choose the C/C++ tab. Under the Category dropbox, select Preprocessor. Put "C:\CppUnit\test\framework" in the textbox for "Additional include directories".

    including additional directories

    Finally, select Build->Rebuild All to create the CppUnit library.


Using CppUnit

Overview

In this section, I will provide you with some general steps on how to go about using CppUnit. The next section illustrates the key steps using an example. My advice is to skim through this section quickly for an overview. Then, as you go through the example in the next section, refer back to this section frequently to get the whole picture.

Assuming that you want to test a class called Parser. The following are the general steps to use the CppUnit framework to test this class:

  1. Write a class (let's call it TestParser) to test the Parser class. This class must inherit the class TestCase which is defined by the CppUnit framework.
  2. Create a constructor for this class, passing a name that is representative of the set of tests for this class as the parameter.
  3. Create a fixture. A test fixture is a set of sample objects that you want to (re)use during testing. For example, you might create a few sample source files for the Parser to parse. CppUnit provides a setUp and a tearDown method to manage the fixture. Therefore, you can eg. create file objects in setUp to open the source files and release these resources in the tearDown method. The important thing to note is that setUp and tearDown will be called for every 'test' that you run.
  4. Each 'test' you perform is represented by the implementation of a method in the test class. For example, if you want to test whether the parser extracts the tokens correctly, you can implement a method called testGetToken. The collection of test methods you implement forms a test suite.
  5. In each test method you create, use the assertion mechanism provided by CppUnit to compare the results of running the test and the results you expected. This will enable you to create repeatable tests as well as saving you lots of time from visually inspecting the results.
  6. Finally, use the textual version of the TestRunner tool to run the tests and collect the results. As each test is run, CppUnit will provide feedback on whether the test ran successfully, or the test failed, or an exception has occurred.

Example

In this section, I will describe how you can use CppUnit using an example. First, you need to start the Visual C++ IDE. Select File->New. A new Window will appear. Under the projects tab, select "Win32 Console Application". Under Location, enter "C:\CS3214s". This directory will be used to store all the files for this project (create the directory if necessary). Next, give the project a name. Under Project Name, enter "tutorial".

creating a new project

You will be prompted for the kind of Console Application - just select "An empty project" and click on the Finish button. A window showing the new project information will be displayed. Click on the Ok button to close it.

creating a console application

Next, you need to create the classes used for the example. You can enter the code using any editor of your choice, placed them in the directory C:\CS3214s\tutorial and then add them to the tutorial project through the IDE (using Project->Add To Project->Files), or you can make use of the IDE to create the necessary files. Take a few minutes to examine the following two classes (.h and .cpp files) to see what they are doing:

Basically, there are two classes: Course and Student. Each Course contains a name eg. CS3214s and an integer grade which ranges from 0 to 100. Each Student has a name, a number as well as a list of course grades. You can add the grade that a student scores at a particular course using the assignGrade method and retrieve the grade of a particular course using the getGrade method. Next, create the test class. The following are the test files I wrote for the Student class (called TestStudent.h and TestStudent.cpp): Notes for the preceding code: Last of all, copy the file TestRunner.cpp from C:\CS3214s\CppUnit\test\textui into C:\CS3214s\tutorial. Add the file to your tutorial project and modifies it as follows:
change:
#include "ExampleTestCase.h"
to:
#include "TestStudent.h"

and

change:
runner.addTest ("ExampleTestCase", ExampleTestCase::suite ());
to:
runner.addTest ("StudentTestCase", StudentTestCase::suite ());
As you write different test classes for your testing, remember to modify (or create) TestRunner.cpp for your own usage.

Now, you are ready to compile and run the tests. Before that, you need to configure some settings for your project. Select Project->Settings and then the C/C++ tab. Under the Category dropbox, select Preprocessor. Put "C:\CppUnit\test\framework, C:\CppUnit\test\textui" in the "Additional include directories" textbox.

adding new directories

Last of all, click on the Link tab and append "C:\CppUnit\ms\culib\Debug\culib.lib" to the string in the "Object/library modules" textbox. Click Ok, we are now ready for testing.

including the cppunit library

Select Build->Rebuild All to start your compilation. You should get some warnings but there shouldn't be any errors. Finally, open your dos prompt and go to C:\CS3214s\tutorial\Debug. Type

tutorial StudentTestCase
If you get the following output, you have successfully completed your unit testing.

running the tests

Exercise

The best way to learn CppUnit is to use it. So, here's a small exercise you can do to get some hands-on practice. Let's say we now extend the Student class by adding a method to find the average grade of all the courses taken by the student. You can add the following piece of code to Student.h and Student.cpp:
// In Student.h under public
// Method to return the average grade
float findAveGrade();

// In Student.cpp
// Method to return the average grade
float Student::findAveGrade() {
  float sum = 0.0, average;

  // sum up the marks in all the courses
  for (int i = 0; i < no_of_courses; i++)
    sum += course_grades[i].getCourseGrade();
  average = sum / no_of_courses;
  return(average);
}
Your job is to write a method in the StudentTestCase class to test this newly created method. Give it a try and see whether you really know how to use CppUnit ;-)

Organizing the project code

As you go through each iteration of your project, you will find the amount of source code increasing. If you do not organize properly, you will soon end up with source files lying all over the directory, making it difficult to find the right file(s) or coordinate code written by different members. In MS Visual C++, you can organize your classes into folders. This is an effective way of partitioning individual member's code. For example, you might create the following folders to store the code of different parts of the SPA:

Organizing the test code

Following the guideline of "Code a little, test a little, code a little, test a little,...", you'll soon find the amount of test code increasing rapidly as the project progresses. You can either place the test code in the same directory or as a sub-folder of the directory containing the set of code you are testing. The important thing is not to sprinkle your test code all over the place - it will reduce the efficiency of your testing process.

References

Unfortunately, there isn't a lot of documentation regarding CppUnit. Instead, you should read up those references in the JUnit Guide to understand the overall framework and apply it in the context of CppUnit. Remember, to maximize the potential of CppUnit, you need to read more and experiment on your own. If you need to, reading the CppUnit's source will also be helpful.