Search code examples
c++unit-testingstructureboost-test

What physical layout for Unit-Tested projects?


At the moment, I'm learning about Unit-Testing and I want to integrate testing to my current (10 files of OpenGL experiments) project. For this purpose I downloaded Boost.Test, and while I can figure out how it works on a single file sample, I have no idea about how to integrate it in my project (I'd like to use static link version).

Are test a different binary from the application itself ? (if it's one binary, how to run it ?) Should I create a test file for every tested class ? How much should my CMakeLists change to reflect this integration ? Is it possible to decouple testing from the application, in a way that I can build my app on a platform where I didn't install boost ?

I know I have many questions, but to put it simply : how is Boost.Test used in real life ?


Solution

  • Weather your project builds a library or executable, I suggest you create an extra test runner executable. In my projects I normally have the following layout:

    /mylib
      CMakeLists.txt
      /inc
        ClassA.hpp
        ClassB.hpp
      /src
        ClassA.cpp
        ClassB.cpp
      /test
        ClassA_test.cpp
        ClassB_test.cpp
        main_test.cpp
    

    As you see there is a test file for every class. This has the main benefit of reducing compilation dependencies. In my CMakeLists.txt I then create my library and the associated test runner

    # Get Boost
    find_package ( Boost COMPONENTS unit_test_framework )
    # Here you set library sources, use file ( GLOB ... ) if you have many
    set ( SOURCES ClassA.cpp ClassB.cpp )    
    add_library ( mylib ${SOURCES} )
    
    if (Boost_FOUND)
      # Here you set test sources, use file ( GLOB ... ) if you have many
      set ( TESTSOURCES ClassA_test.cpp ClassB_test.cpp )    
      # This creates the test runner
      add_executable (  mylib_test_runner ${TESTSOURCES} )
      # Here the tests of the runner are linked to the related library and Boost
      target_link_libraries ( mylib_test_runner mylib ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} )
    endif ( )
    

    The file main_test.cpp is only there to automatically generate the main function for the test runner

    #define BOOST_TEST_MODULE MyTestSuite
    #define BOOST_TEST_DYN_LINK
    #include <boost/test/unit_test.hpp>
    

    Then, for example, ClassB_test.cpp might have the following layout:

    #include "../inc/ClassB.hpp"
    #include <boost/test/unit_test.hpp>
    
    BOOST_AUTO_TEST_SUITE ( ClassBTest )
    
    BOOST_AUTO_TEST_CASE ( TestFoo )
    {
      BOOST_CHECK(true);
    }
    
    ...
    
    BOOST_AUTO_TEST_SUITE_END() // ClassBTest
    

    So wrapping up:

    • Are test a different binary from the application itself? - Yes, that is possible and certainly helpful.
    • If it's one binary, how to run it? - In this case: ./mylib_test_runner
    • Should I create a test file for every tested class? - I suggest you do.
    • How much should my CMakeLists change to reflect this integration? - See the example.
    • Is it possible to decouple testing from the application, in a way that I can build my app on a platform where I didn't install boost? - The check for Boost_FOUND takes care of this, you could also add an option to your CMakeLists.txt and check against that. I personally think this is even better.