In this post I will show you how to perform unit testing with Boost.Test. If you do not have the boost libraries installed, read my post “Unit Testing with Boost.Test – Installing Boost.Test”.
Boost Test Library has following four components:
- The Execution Monitor whose purpose is function level uniformed exception handling and error reporting.
- The Program Execution Monitor relieves users from messy error detection and reporting duties by providing a replacement function main() which uniformly detects and reports the occurrence of several types of errors, reducing them to a uniform return code which is returned to the host environment.
- Minimal Testing Facility provides only minimal basic facilities for test creation without any configuration options and supplies a limited set of testing tools.
- Unit Test Framework is the focus of this post. It is an easy to use and flexible solution for C++ unit test implementation and organization.
For the rest of this post we will focus only on the unit testing framework (refered to hereinafter as UTF).
Boost Test Library components can be used by either linking to the precompiled library or by including the single-header file. For example, to use the UTF you may either include the <boost/test/unit_test.hpp> and link with unit_test_framework shared library or include <boost/test/included/unit_test.hpp> in which case there is no need to link with any precompiled component.
Writing First Test Case (Using Single UTF Header)
To get a grip on how to use Boost.Test in both the shared library and included hearder form, we will first write a program that uses the single UTF header and then change that program to use the pre-compiled UTF shared library. So fire up your favorite IDE, create a new C++ project and paste the following code in your `main.cpp` and compile the project.
In case you encounter errors about `unit_test.hpp` not found, check your include library paths and make sure you have included $BOOST_HOME as a include file location.
#define BOOST_TEST_MODULE MyTest
#include <boost/test/included/unit_test.hpp>
int add( int i, int j ) { return i + j; }
BOOST_AUTO_TEST_CASE( my_test )
{
// seven ways to detect and report the same error:
BOOST_CHECK( add( 2,2 ) == 4 ); // #1 continues on error
BOOST_REQUIRE( add( 2,2 ) == 4 ); // #2 throws on error
if( add( 2,2 ) != 4 )
BOOST_ERROR( "Ouch..." ); // #3 continues on error
if( add( 2,2 ) != 4 )
BOOST_FAIL( "Ouch..." ); // #4 throws on error
if( add( 2,2 ) != 4 ) throw "Ouch..."; // #5 throws on error
BOOST_CHECK_MESSAGE( add( 2,2 ) == 4, // #6 continues on error
"add(..) result: " << add( 2,2 ) );
BOOST_CHECK_EQUAL( add( 2,2 ), 4 ); // #7 continues on error
}
The command line that I used to compile and run the above code and the program output is given below:
$ g++ -o main main.cpp -I/usr/local/include/boost/trunk/
$ ./main
Running 1 test case...
*** No errors detected
$
The above code shows seven different ways to detect and report errors in the code. The description of these different tools is available on Boost.Test website so I won’t repeat that here. You should play with the code and change the success conditions to see what happens.
Writing First Test Case (Using Boost.Test Pre-Built Library)
To use the Boost.Test as a pre-built library component (which is the preferred way for large projects) first of all change the path for the include file in the previous example from
#include <boost/test/included/unit_test.hpp>
to
#include <boost/test/unit_test.hpp>
You have two choices to use Boost.Test pre-compiled binary with your project. You can use it as either a shared library (libboost_unit_test_framework.so) or statically compile your program with it (libboost_unit_test_framework.a).
To statically build your program, use the following command:
g++ -o main main.cpp -I/usr/local/include/boost/trunk/ -L/usr/local/include/boost/trunk/stage/lib/ -static -lboost_unit_test_framework
Note the -static compiler option before the library name. It instructs `g++` to statically link the library with the program.
In order to use the boost unit test framework as a shared library, add
#define BOOST_TEST_DYN_LINK
preprocessor directive just before you include boost test header file as below:
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
and build with the following command:
g++ -o main main.cpp -I/usr/local/include/boost/trunk/ -L/usr/local/include/boost/trunk/stage/lib/ -lboost_unit_test_framework
If you now run this program you might get the following error:
./main: error while loading shared libraries: libboost_unit_test_framework.so.1.45.0: cannot open shared object file: No such file or directory
This is because we are now using Boost.Test UTF as a shared library and for the program to execute, it must find the required libraries. There are three different ways to do that:
- You can add library directories to be included during dynamic linking to the file /etc/ld.so.conf OR
- You can add specified directory to library cache using ldconfig OR
- You can specify the environment variable `LD_LIBRARY_PATH` to point to the directory paths containing the shared object libraries
After you have updated the library search path using either one of the above methods, you can run the program as before and verify that all tests are successful.
Congratulations, you are now able to use Boost.Test in your programs to write basic unit tests. In a future post, I will show you how to use the UTF in more complex programming scenarios.