At SparkPost, we put a lot of time and effort into testing our code. Our platform is written in C, and recently I researched integrating with a unit testing framework called “CppUTest”, which provides xUnit-style testing for C/C++. This framework is robust, feature-rich, and under active development, which makes it a great choice. It also provides a C integration layer which made it easy to use with our platform C code even though most of the framework is C++. This tutorial covers how to get started with CppUTest on your own projects.

Downloading CppUTest

The CppUTest project page is available here, and the repository is on github. It’s also included in the package management repositories for many linux distros, as well as homebrew on Mac OS. The examples that follow were executed on Mac OS X, but they’re derived from code written for Red Hat, the OS our platform runs on.

The basics are well documented on CppUTest’s home page. We’re going to breeze through that and get to some of the more interesting features.

Laying the Foundation

First things first, let’s write some code!

Our test project will have a ‘main’ file and will include a utility library called ‘code’. The library will provide a simple function that returns 1 (for now). The files will be laid out like this:

Let’s start by writing the src/ files

Now, let’s do the tests, which will live in the t/ directory.  The first thing to do is to set up a test runner which will run our test files. This is also the 'main'  function that will execute once this is all compiled:

Now we can write our first test module:

Next, we need to write makefiles.  We’ll need two: one for the project files under src/, and one for the tests.

Project Makefile

The project makefile will be at the same level as the ‘src’ and ‘t’ directories at the root of the project. It should look like this:

Note that this uses make -C  for the test targets – meaning that it will call make  again using the makefile in the test directory.

At this point we can compile the ‘src’ code with the makefile and see that it works:

Tests Makefile

For the tests, things are a little more involved since we need to properly load and integrate with the CppUTest library.

The CppUTest repository provides a file called “”. It provides a lot of functionality which makes building with CppUTest simple. The file lives under the “build” directory in the git repository. For this tutorial we’re going to assume it’s been copied to the ‘t/’ directory. It can be used as follows:

Note that CPPUTEST_HOME must be set to wherever CppUTest was installed. If you’ve installed a distro package, this will typically be under /usr/local on a linux/mac system. If you’ve checked out the repo on your own, it’s wherever that checkout is.

These options are all documented in also adds a few makefile targets, including the following:

  1. all – builds the tests indicated by the makefile
  2. clean – removes all of the object and gcov files generated for the tests
  3. realclean – removes any object or gcov files in the entire directory tree
  4. flags – lists all of the configured flags used to compile the tests
  5. debug – lists all the source files, objects, dependencies, and ‘stuff to clean’

Code Coverage

Unit testing would not be complete without a coverage report. The go-to tool for this for projects using gcc is gcov, available as part of the standard suite of gcc utilities. Cpputest integrates easily with gcov, all you need to do is add this line to the makefile:

Next, we need to make sure that the script from this repo is in ‘/scripts/’ relative to wherever you set ‘CPPUTEST_HOME’ to be. It also needs to have execute perms.

In the example Makefile, it would be deployed to ‘/usr/local/scripts/’. If you’re running CppUTest from a repo checkout, everything should work without modification.

With that in place, you can simply run ‘make gcov’ and the analysis will be generated for you. In our case we’ll need to ‘make -B’ to rebuild the object files with gcov enabled:

This will output a number of files to a new ‘gcov’ directory. These are:

  1. code.cpp.gcov – the actual ‘gcov’ file for the code being tested
  2. gcov_error.txt – an error report (in our case, it should be empty)
  3. gcov_output.txt – the actual output of the gcov command that was run
  4. gcov_report.txt – a summary of the coverage for each file under test
  5. gcov_report.txt.html – an html version of gcov_report

Cpputest Memory Leak Detection

Cpputest allows you to automatically detect leaked memory by redefining the standard “malloc/free” family of functions to use its own wrappers instead. This allows it to quickly catch leaks and report them for each test execution. This is enabled by default in, so it’s already on with the steps outlined so far.

To illustrate, let’s leak some memory in test_func() !

Going back to code.c, we add a malloc()  to the function, like so:

Now, after recompiling, the following error is produced:

This shows which test caused the leak, where the leak happened in the source code, and what was in the leaked memory. Very helpful!

There are a couple of caveats with this feature:

  1. Cpputest is using preprocesser macros to dynamically redefine all calls to the standard memory management functions. That means it will only work for calls in the source code under test since that’s what’s compiled in with CppUTest’s overrides. Leaks in linked libraries will not be caught.
  2. Sometimes memory which is allocated for the entire life of the process is not meant to be freed. This can make a lot of spammy errors if you’re testing a module with this behavior. To disable the leak detection, you can do this:

Interested in More?

This is just the tip of the iceberg when it comes to all the features contained in this tool. Besides the basics discussed here, it also has a mocking framework, a direct C integration layer, and a plugin framework, to name a few significant ones. The repo also contains a whole directory of helper scripts that can help automate some of the routine parts of working with the framework.

I hope the information here helps you improve your C/C++ code quality with this great tool! We’d love to hear about what you’ve built. Reach out to us on Twitter or Slack and let us know what you’re working on.

-Yaakov Kuperman
Manager, Site Reliability Engineering