In this post, I will describe how to start making unit tests in C++ with Boost.Test.
The Boost libraries are a large collection of source libraries for C++ programmers. There are many useful libraries in Boost. One of those libraries is Boost.Test, a library for writing and organizing test programs.
Most xUnit test frameworks exploit some form of reflection in a programming language to dynamically execute test code within a test framework. C++ does not have support for reflection and requires that the user register their test code with the test framework. Boost.Test hides the test framework and the registration mechanism behind a series of macros, resulting in a header only library for unit testing.
Unit tests are an important part of modern programming discipline. They are the underpinning of a development style called test-driven development, where you first write a failing test and then write production code to satisfy the test. In this style of development production code is only written in response to a failing test. In turn, the tests are written in response to requirements for changing existing functionality or creating new functionality.
The interesting thing about this sort of development style is that because you’ve written the code in response to a test, you automatically have production code that is designed to be testable. This development style also tends to produce smaller objects that adhere to the single responsibility principle, in other words an object that does one thing only. Smaller objects are easier to test. Smaller objects are more likely to find situations where they can be reused. Of course, you also end up with an ever-increasing regression suite that you can run over your objects to make sure that a change in one place didn’t break something in code you’ve already written.
Because most xUnit test frameworks are inspired by JUnit, the defacto test framework for Java, they rely on reflection to get the job done. Without reflection, C++ lagged in having a defacto test framework that supported a wide variety of testing scenarios. With the Boost.Test library, we can write unit tests in C++ with a minimal amount of fussing around with the registration mechanisms.
In order to use Boost.Test, you will need to install it and configure Visual Studio’s C++ project directories to look for Boost’s files. I recommend that you use the prepackaged MSI installer for Boost that will allow you to select which precompiled libraries you might like to use (debug, release, multi-threaded, etc.). To use Boost.Test you will only need header libraries, so you can download the zip distribution and unpack it to a suitable folder if you wish to avoid the large download of precompiled libraries. (Some libraries in Boost require are not header-only libraries and require building.) Either way, you can find what you need from the boost download page. This article was created with the 1.35 release, but should work with any subsequent release of boost. Finally, configure the C++ include directories to include the directory where you installed boost. This should be the directory containing the folders “boost”, “doc”, “lib”, etc.
So how do we organize unit tests with Boost.Test? First, all the tests are organized together into a single executable program that executes all the registered test cases one by one. Boost provides a standard implementation of main that executes all the registered test cases and macros to create a test case and register it with the framework. In Visual Studio, simply follow these steps:
- Create a new Win32 Console Project called “Test”.
- Accept the default settings in the Win32 Application Wizard.
- Replace the contents of
Test.cppwith the following source code:#define BOOST_TEST_MAIN #include <boost/test/unit_test.hpp>
- Change the project options for
Test.cppto not use precompiled headers. Remember to change the options for both Debug and Release configurations. - Compile and link the project.
- Run the project to see the following output:
Test setup error: test tree is empty
The return value of the executable will be non-zero since an error was encountered during test execution.
- Add the following line to
stdafx.h:#include <boost/test/unit_test.hpp>
This will include the Boost.Test library in all source files.
Now we are ready to write our first test case. Create a new cpp source file called Test1.cpp and add the following code to the file:
#include "stdafx.h"
BOOST_AUTO_TEST_CASE(Test1)
{
BOOST_REQUIRE(true);
}
Compile and link the project and run the test executable again to get the following output:
Running 1 test case... *** No errors detected
So now we have created a test executable and a simple unit test that doesn’t do much more than exercise the test framework. What we’d also like is for our build to run the unit tests every time we compile and fail the build when the unit tests fail. We can take care of that by configuring our unit tests to run as a Post-Build event on the unit test project:
- Open the project properties dialog for the Test project.
- Select “All Configurations” from the Configuration combobox in the upper left.
- Expand the Configuration Properties / Build Events category in the tree view on the left and select Post-Build Event.
- For the value of the Command Line property enter the value “$(TargetPath)”.
- For the value of the Description property enter the value “Running unit tests…”.
- Click OK.
To check that we’ve configured everything properly, change “BOOST_REQUIRE(true);” to “BOOST_REQUIRE(false);” to force the unit test to fail. Now build the solution and the build should fail with output similar to the following in the Output pane in Visual Studio:
1>------ Build started: Project: Test, Configuration: Debug Win32 ------ 1>Compiling... 1>Test1.cpp 1>Linking... 1>Embedding manifest... 1>Running unit tests... 1>Running 1 test case... 1>c:/tmp/code/boost.test/test/test1.cpp(5): fatal error in "Test1": critical check false failed 1>*** 1 failure detected in test suite "Master Test Suite" 1>Project : error PRJ0019: A tool returned an error code from "Running unit tests..." 1>Build log was saved at "file://c:\tmp\Code\Boost.Test\Test\Debug\BuildLog.htm" 1>Test - 2 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The Visual Studio errors window will contain an entry for the failed assertion that you can double-click to take you to the location in the test code that failed.
This covers the basics of using Boost.Test for unit testing in C++ under Visual Studio. Part 2 will cover more of the macros provided by Boost.Test for making assertions and organizing your tests.
[Updated to favor BOOST_REQUIRE over BOOST_CHECK.]
4-July-2009 at 11:25 pm
I like it!
PS: It should be mentioned that there is a non-header-only version of Boost.Test, which cuts down on compile time.
4-July-2009 at 11:46 pm
That’s a good point. I’ve used the header-only version with the headers included in the precompiled header and has been OK so far. When you accumulate thousands of tests, it might be faster to switch to the library version. To start off I like header-only libraries because it simplifies the use of boost.
5-July-2009 at 9:56 am
[...] Unit Tests With Boost.Test, Part 2 5-July-2009 — legalize In Part 1 of this series, I discussed how to setup a basic C++ unit test project that executed the unit tests [...]
12-July-2009 at 2:21 pm
[...] with the builders are suites of C++ unit tests written with Boost.Test for testing all the functionality of the builders. You will need a boost distribution if you want [...]