Search code examples
eclipsepackageprogram-entry-pointc++98boost-test

C++ Boost Test, package structure, and Eclipse project settings


I'm using C++98, and besides the standard library, I only have access to an old version of Boost (which thankfully has Boost Test). The documentation though is daunting, long, and I just don't know where to begin.

I have some experience doing unit testing in Java (and I'm looking for unit testing in C++), and I've seen test packages that contain the unit test code separate from the src package, and I also saw Where do you put your unit test? as well as Unit Testing with Boost and Eclipse. Their suggestions vary, and present reasoning for different packaging structures for separating test code from production code, or having them together.

Before I even started looking into Boost Test, I created this structure within Eclipse (perhaps erroneously):

-- ProjectName
   |-- Debug
   |-- src
   |-- test

and I wrote another main method to run test functions. Eclipse didn't like that, because I had two main methods in the same project. I fumbled around through Project Properties and didn't find anything useful for separating my production code from test code when building (linking, really). My temporary fix was to just use g++ in the terminal and ad hoc compile just my "test" code.

I found something suggesting on Boost::Test -- generation of Main()? that Boost actually generated its own main method, so this is currently my plan of attack for unit testing, especially for having a library of testing tools already available.

  • What is the conventional way of organizing unit tests for C++?
  • How do I get started with Boost Test? (Boost is already installed)
  • Is there anything I need to change in Eclipse to be able to run my Boost unit tests separate from my production code within the IDE? (One of the nice things about IntelliJ, with Java, is how it'll automatically run any main method you like with a click) -- The goal here to be able to build and run my tests within Eclipse.
  • Should my tests be in a separate Eclipse project? (this was suggested in an answer to the second SO question I linked)

Edit: I found this article for an introduction to Boost Test, but it doesn't discuss how it can be handled within an IDE setting.


Solution

  • I figured out how to do this on my own, and I'll document my solution for others who are just starting with C++ as well and need to do testing of their code. There currently is no good introduction anywhere that I could find. Here are the resources that I used though (and found useful):

    The C++ convention for testing is like that of other coding languages, just write your tests in a directory called test under the project. Using Boost Test requires that you link the unit test framework: -l boost_unit_test_framework which in Eclipse:

    Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Linker, Libraries, and add the library name boost_unit_test_framework (add -mt to the name if you require multithreading; additionally, once the testing build configuration exists, you can go back and choose just that configuration to link the library -- it'll reduce the size of your executable for your other builds).

    To be able to run the unit tests in Eclipse separate from your main method, we need to establish a new build configuration. That way, Eclipse knows to exclude your source file with a main method when you're executing your tests.

    Click on Project, Build Configurations, Manage..., and select New... and call it Test (or something other than test). Choose your existing configuration so that we'll inherit properties from the production build.

    Next, we need to differentiate the build configurations from one another so when we build them, they actually correspond to the production and test builds.

    Right click on test, Resource Configurations, Exclude from Build..., and select the builds that represent your production build (i.e. Debug and or Release). Once done with that, right click on your source file with your main method, and exclude that from the Test build.

    There's still some things we need to change. We don't have any test code yet, but we still can't run our test build, nor would our test build know about resources existing in src because Eclipse wouldn't automatically include those source files. They're practically invisible to your test code in test.

    Right click on your project, go to Properties, C/C++ Build, Settings, Tool Settings, GCC C++ Compiler, Includes, and add the path /.../workspace/ProjectName.

    Now to be able to run your test build in Eclipse, it needs to know what executable you're expecting the IDE to run.

    Click on Run, Run Configurations..., and looking at your current run configuration, consolidate these settings by giving, for example, a debug build the name "Debug Build", the C/C++ Application "Debug/Artifact_Name", and the Build Configuration "Debug". Next, create a new run configuration, and call it something like "Test Build", set C/C++ Application to "Test/Artifact_Name", and ensure the build configuration is Test.

    Now you'll be able to switch between running production code and test code by selecting either the "active" build configuration or running the correct run configuration.

    Finally, here's an example of a unit test with Boost Test once all of this is set up:

    //unit_tests.cpp
    #define BOOST_TEST_DYN_LINK
    #define BOOST_TEST_MODULE someModuleName
    #include <boost/test/unit_test.hpp>
    #include <src/some_object.h>
    
    struct template_objects {
        some_object x;
        template_objects() {
            BOOST_TEST_MESSAGE("Setting up testing objects");
        }
        ~template_objects() {
            BOOST_TEST_MESSAGE("Tearing down testing objects");
        }
    }
    
    BOOST_FIXTURE_TEST_SUITE(testSuiteName, template_objects)
    
    BOOST_AUTO_TEST_CASE(testCase1) {
        x.update();
        BOOST_CHECK(x.is_up_to_date());
    }
    BOOST_AUTO_TEST_CASE(testCase2) {
        BOOST_CHECK(x.is_not_up_to_date());
    }
    
    BOOST_AUTO_TEST_SUITE_END()
    

    This demonstrates some critical things about using Boost Test:

    • defining BOOST_TEST_DYN_LINK is recommended; you need to define a way of linking the testing framework before including any of Boost's libraries
    • you must name the "module" something, doesn't have to be the file name
    • to get automated setup up and teardown of objects before entering test cases, Boost Test has fixtures, which allow you to call an object's pre-existing state multiple times
    • the struct is what groups these fixtures, and it's implied that your object should have a well defined constructor and destructor for automatic scoping (if you didn't call new, you don't need delete in teardown)
    • test suites are just a way of logically grouping your test cases (I haven't tested it yet, but you can probably break up your suites into multiple files for better logical separation)

    Additional tidbit: to make Boost Test more verbose, go to your run configuration for the test build, and add the argument --log_level=test_suite.