c++boostfixturesboost-testmt

Execute one test case several times with different fixture each time


I have a test case that I want to execute for different states of database. I insert objects to DB in fixture (and I'd like to keep it that way). I want to make method for initialization of DB virtual and specialize fixture for different configurations in DB.

One way I can think of is to do something like:

void doTest(){
    //test code here
}

BOOST_FIXTURE_TEST_CASE(test1, fixture1)
{
    doTest();
}

BOOST_FIXTURE_TEST_CASE(test2, fixture2)
{
    doTest();
}

BOOST_FIXTURE_TEST_CASE(test3, fixture3)
{
    doTest();
}

But is there a cleaner, neater way? Or maybe I shouldn't do this altogether? I will appreciate any advice from testing experts.


Solution

  • You can use BOOST_FIXTURE_TEST_CASE_TEMPLATE to instantiate multiple tests:

    #define BOOST_TEST_DYN_LINK
    #define BOOST_TEST_MODULE TestModuleName
    #include <boost/test/unit_test.hpp>
    #include <boost/mpl/vector.hpp>
    
    struct Fixture1 { int i; Fixture1() : i(1) {} };
    struct Fixture2 { int i; Fixture2() : i(2) {} };
    struct Fixture3 { int i; Fixture3() : i(3) {} };
    
    typedef boost::mpl::vector<Fixture1, Fixture2, Fixture3> Fixtures;
    
    BOOST_FIXTURE_TEST_CASE_TEMPLATE(Test, T, Fixtures, T){
        std::cout << T::i << "\n";
    }
    

    Will print

    1
    2
    3
    

    This code instantiates an own test case for each type in the mpl::vector 'Fixtures'. Each Fixture type will be passed in as T (second parameter of BOOST_FIXTURE_TEST_CASE_TEMPLATE) and T will be used as fixture for the test case (last parameter).

    Caveat

    Because of the template nature of the test case (class) you need to prepend T:: to access the fixtures members to indicate that they are (template parameter) dependent names.

    Improvement

    Because BOOST_FIXTURE_TEST_CASE_TEMPLATE is so generic, one might want to define a handy "shortcut" which is more explicit about what is being done:

    #define MULTI_FIXTURE_TEST_CASE(NAME, TPARAM, ...) \
            typedef boost::mpl::vector<__VA_ARGS__> NAME##_fixtures; \
            BOOST_FIXTURE_TEST_CASE_TEMPLATE(NAME, TPARAM, NAME##_fixtures, TPARAM)
    
    MULTI_FIXTURE_TEST_CASE(Test, T, Fixture1, Fixture2, Fixture3){
        std::cout << T::i << "\n";
    }
    

    As you can see it somewhat hides the mpl::vector. I think it would be best to define this macro in its own header which also does #include <boost/mpl/vector.hpp> to avoid missing the dependency. The fixtures list name is the name of the test case plus '_fixtures' so it should hopefully not clash with existing names and be somewhat meaningful.