Posts Tagged ‘unit testing’

Unit Testing with Boost.Test – Writing Your First Test Case

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: " &lt;&lt; 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:

  1. You can add library directories to be included during dynamic linking to the file /etc/ld.so.conf OR
  2. You can add specified directory to library cache using ldconfig OR
  3. 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.

Share

Unit Testing with Boost.Test – Installing Boost.Test

if Jeff Atwood and Mr. T can not convince you of the benefits of unit testing then I don’t know who else can. So I won’t press the issue of writing test cases before coding or unit testing at all. Instead, as you are reading this post, I am assuming that you are not “the fool” being pitied upon by Mr. T and actually consider writing test cases a coding prerequisite.

Now that we have agreed upon (at least I am assuming we have) the importance of unit testing, we’ll come to the title of this post “Unit Testing with Boost.Test”. Why Boost.Test (or any other testing framework for that matter)? You can very well write test cases using `assert` macros but this approach is very trivial and rigid and does not lend itself to flexibility and versatility in the writing of test cases (as we shall see in the next part of this post). These limitations render the `assert` macro unsuitable for more complex projects. Boost.Test is an easy to use and flexible way to write use cases and is part of the boost c++ libraries which is a set of standards compliant, cross platform c++ libraries.

In this post I will show you how to install the boost libraries. You can download a version appropriate for your platform from http://www.boost.org/users/download/#releases and extract to a folder in a common location (e.g. /usr/local/include/boost). If you’d rather checkout an svn snapshot, you can do an svn checkout by issuing following command in a shell:
$ svn co http://svn.boost.org/svn/boost/trunk boost-trunk
Please visit http://www.boost.org/users/download/#repository for more instructions.
If you are using Ubuntu, you can also do
$ sudo apt-get install libboost-test-dev
But I don’t recommend this approach as the packages are somewhat out of date.

I will be using version 1.45.0 of boost libraries for this article which is the latest at the time of this writing. if you have any previous version installed, please check the changelog to see if you need to upgrade to this version. eventhough its always best to use latest release build of any library, some of your projects might break with new changes so be carefull to read the changelog carefully before upgrading.

If you need more info about installing boost libraries, please visit this page if you are on *nix or go here if you are on Windows platform.

Now that we have installed boost libraries, we need to set up our development environment but before that there is something else that we need to take care of. The boost libraries are mostly header only. That is, they consist entirely of header files containing templates and inline functions and require no separately-compiled library binaries but there are some libraries that must be built separately and then there are some libraries that can _optionally_ be compiled separately. Boost.Test is of the latter form. You can use it as a header only library or you can pre-compile it and link your project to this binary. It is recommended that this library be used as a separately compiled binary as it will greatly reduce the compilation time for your project.

Building the Boost.Test library is not very complicated. Boost has its own build system which is accessible from the boost installation directory. To build Boost.Test perform following steps:
`cd` to the boost installation directory (assuming your installation directory is /usr/local/include/boost/trunk)
$ cd /usr/local/include/boost/trunk
To see all available options
$ ./bootstrap.sh --help
To see a list of all libraries that need to be / can be built do
$ ./bootstrap.sh --show-libraries
You probably only want to build Boost.Test so type following in a shell
$ ./bootstrap.sh --with-libraries=test
When this command successfully finishes execution you will get a message indicating that bootstrapping has been successfully done. Next you will actually build the library. Type following on the shell
$ ./bjam
Once `bjam` finishes successfully, it will place the library binaries in $BOOST_HOME\stage\lib directory.

Verify the existance of `libboost_unit_test_framework.a` and `libboost_unit_test_framework.so` in that directory. Your Boost.Test installation is ready. In the next post we will set up a sample project and look at how we can use Boost.Test in our projects to benefit from this great testing framework.

Share
Return top
 

Switch to our mobile site