Unit testing application code in embedded applications is a fundamental need that embedded developers often overlook. At first, glance, getting a unit test harness up and running can seem complicated. However, developers can get a unit test harness environment up and running relatively quickly. This post will explore Cpputest and how developers can leverage existing resources to get an environment up and running quickly.
Introduction to Cpputest
Cpputest is a C/C++-based testing framework that is used for unit testing and test-driving code. In general, Cpputest is used for testing C and C++ applications. The framework provides developers with a test harness that can execute test cases. Cpputest also offers a set of assertions that can be used to test assumptions. If the result is not correct, then the test case is marked as having failed the test.
Cpputest provides a free, open-source framework for embedded developers to build unit tests to prove out application code. With a bit of extra work, developers can even run the tests on target if they so desire. In general, I use Cpputest to test my application code that exists above the hardware abstraction layer.
Several different installation methods can be used to set up Cpputest that can be found on the Cpputest website. The first is to install pre-packaged installed on Linux or MacOS. (If you want to install on Windows, you’ll need to use Cygwin or a similar tool). Alternatively, a developer can clone the Cpputest git repository.
If you are looking to get started quickly and experiment a bit, I recommend a different approach. James Grenning has put together a Cpputest starter project that has everything a developer needs to get started. The start project includes a docker file that can be loaded and a simple command to install and configure the environment. If you want to follow along, clone the Cpputest starter project to a suitable location on your computer. Once you’ve done that, you can follow James’ instructions in the README.md or follow along with the rest of this section.
Before getting too far, it’s essential to make sure that you install docker on your machine. Mac users can find instructions here. Windows users can find the instructions here. For Linux users, as always, nothing is easy. The installation process varies by Linux flavor, so you’ll have to search a bit to find the method that works for you.
Once docker is installed and running, a developer can use their terminal application to navigate to the root directory of the Cpputest starter project directory and then run the command:
docker-compose run cpputest make all
The first time you run the above command, it will take several minutes for it to run. After that, the command will download docker images, clone and install Cpputest and build the starter project. At this point, you would see something like the following in your terminal:
As you can see above, there was a test case failure in tests/MyFirstTest.cpp on line 23 along with an ERROR: 2 message. This means that Cpputest and James’ starter project is installed and working correctly.
Leveraging the Docker Container
The docker-compose run command causes docker to load the cpputest container and then make all. Once the command has been executed, it will leave the docker container. In the previous figure, that is the reason why we get the ERROR: 2. It’s returning the error code for the exit status of the docker container.
It isn’t necessary to constantly use the “docker-compose run cpputest make all” command. A developer can also enter docker container and stay there by using the following command:
docker-compose run --rm --entrypoint /bin/bash cpputest
By doing this, a developer can then simply use the command “make” or “make all”. The advantage of this is that it streamlines the process a bit and removes the ERROR message returned when exiting the docker image from the original command. So, for example, if I run the docker command and make, the output from the test harness now looks like the following:
To exit the docker container, all I need to do is type exit. I prefer to stay in the docker container, though, to streamline the process.
Test Driving Cpputest
Now that we have set up the Cpputest starter project, it’s easy to go in and start using the test harness. We should remove the initial failing test case before we add any tests of our own. This test case is in /tests/MyFirstTest.cpp. The file can be opened using your favorite text editor. You’ll notice from the previous figure that the test failure occurs at line 23. The line contains the following:
FAIL(“Your test is running! Now delete this line and watch your test pass.”);
FAIL is an assertion that is built into Cpputest. So the first thing to try is commenting out the line and then running the “make” or “make all” command. If you do that, you will see that the test harness now successfully runs without any failed test cases, as shown below:
Now you can start building out your unit test cases using the assertions found in the Cpputest manual. The developer may decide to remove MyFirstTest.cpp and add their testing modules or start implementing their test cases. It’s entirely up to what your end purpose is.
We’ve briefly discussed how to get up and running with Cpputest quickly. Working with Cpputest is straightforward, and the results can be compelling. Developers can leverage their test harnesses and assertions to check that code is working as expected. If something is amiss, running the test harness will point the developer to the failing test case and provide the line number for the failed test. Test harnesses can help developers perform automated regression testing and quickly identify bugs in their code.
Developers don’t necessarily have to use Cpputest. There are many unit test harnesses available. However, embedded developers need to be using some type of test harness, and Cpputest is easy to get up and running and integrated into nearly any build process.