10

Is it possible to have the fixture initialized only once and use it in multiple test cases within the same test suite? In the following example, fixture is constructed and destructed multiple times:

struct F {
    F() : i( 0 ) { BOOST_TEST_MESSAGE( "setup fixture" ); }
    ~F()         { BOOST_TEST_MESSAGE( "teardown fixture" ); }

    int i;
};


BOOST_FIXTURE_TEST_SUITE( s, F )

BOOST_AUTO_TEST_CASE( test_case1 )
{
    BOOST_CHECK( i == 1 );
}

BOOST_AUTO_TEST_CASE( test_case2 )
{
    BOOST_CHECK_EQUAL( i, 0 );
}

BOOST_AUTO_TEST_SUITE_END()

But I want the fixture to be constructed only once as the test suite begins and shared among all the test cases within it. Is it possible? The destructor would be called after exiting the test suite.
I am using Boost Test Framework but have no problem using other frameworks like UnitTest++.

congusbongus
  • 13,359
  • 7
  • 71
  • 99
  • The intention of the fixture is to prepare the environment for all test case. Why should it be necessary to prepare it before the first case but not for the others? – harper Apr 10 '13 at 06:14
  • 1
    @harper Suppose that I am opening a socket to be used in all test cases. I don't want the to open and close the socket for each test case. I want to open it only once, use it in multiple test cases and then close it after the last test case is done. –  Apr 10 '13 at 06:17
  • 1
    http://boost.2283326.n4.nabble.com/Boost-Test-Initialize-fixture-only-once-td2626388.html – Evgeny Panasyuk Apr 10 '13 at 06:35
  • @Meysam Especially for a socket you should try to isolate the tests. When test n closes (by accident) the socket you can see that test n+1 fails. Marks response shows a way with a global fixture. You should check if your would use it or if you should keep the isolation idea. – harper Apr 10 '13 at 14:00
  • This feature is more or less directly implemented in boost.test, see [this link](http://www.boost.org/doc/libs/1_64_0/libs/test/doc/html/boost_test/tests_organization/fixtures/per_test_suite_fixture.html). The UTF takes care of the setup/teardown of the fixture, but you cannot access the fixture class as for the snippet you have. You have instead to provide eg. static methods for accessing the instance. – Raffi Jun 28 '17 at 19:09

2 Answers2

26

Each test case is derived from the Test Suite Fixture, which is constructed at the start of each test case and destructed when it completes (in your case both test_case1 & test_case2 are derived from F ). The fixture configures and cleans up the environment for each individual test case.

For unit-testing this is usually the preferred strategy - each test case is stand alone and completely atomic.

In some scenarios (e.g. integration testing ) it might be preferable to acquire an expensive resource once and hold onto it over all test cases. This can be done via a GLOBAL FIXTURE, which is constructed at the start of the test run and destructed when the test exits.

If any test cases require a different setup / configuration of the global resources then a GLOBAL FIXTURE cannot be used and you should re-think your testing strategy so that each test case configures and cleans up its own environment.

Unfortunately test cases do not have direct access to the global test fixture, ergo you will need to provide a mechanism that allows them to access the resource (e.g. via a global variable or singleton).

In the example below MyFixture is a singleton that holds the resource. e.g.

struct MyFixture
{
    static MyFixture*& instance() { static MyFixture* s_inst = 0;
    return s_inst; }

    MyFixture()
    {
        instance() = this;
        x = 10;
        BOOST_TEST_MESSAGE( "setup fixture" );
    }

    ~MyFixture()
    {
        BOOST_TEST_MESSAGE( "teardown fixture" );
    }

    int x;
};

BOOST_GLOBAL_FIXTURE(MyFixture)


BOOST_AUTO_TEST_CASE(TEST_1)
{
    BOOST_CHECK(MyFixture::instance()->x == 10);
    MyFixture::instance()->x = 12;
}
BOOST_AUTO_TEST_CASE(TEST_2)
{
    BOOST_CHECK(MyFixture::instance()->x == 12);
}
mark
  • 7,381
  • 5
  • 36
  • 61
1

It is possible but it requires you to use BOOST_AUTO_TEST_SUITE together with the boost::unit_test::fixture decorator instead of BOOST_FIXTURE_TEST_SUITE. IT is also worth noting that while this will work you will not be able to access the member variables of F inside your test cases. Tip: Just put them outside the struct instead like I do below with i. See here and here for more information in the boost documentation.

struct F {
F()  { BOOST_TEST_MESSAGE( "setup fixture" ); }
~F() { BOOST_TEST_MESSAGE( "teardown fixture" ); }
};

int i = 0;

BOOST_AUTO_TEST_SUITE( s, *boost::unit_test::fixture<F>())

BOOST_AUTO_TEST_CASE( test_case1 )
{
    BOOST_CHECK( i == 1 );
}

BOOST_AUTO_TEST_CASE( test_case2 )
{
    BOOST_CHECK_EQUAL( i, 0 );
}

BOOST_AUTO_TEST_SUITE_END()