Specify constructor arguments for a Google test Fixture

烈酒焚心 提交于 2019-12-05 02:03:21
Marko Popovic

As suggested by another user, you cannot achieve what you want by instantiating a fixture using a non-default constructor. However, there are other ways. Simply overload the SetUp function and call that version explicitly in the tests:

class TheClassTest : public ::testing::Test {
protected:
    TheClassTest() {}
    virtual ~TheClassTest() {}
    void SetUp(const std::string &filename) {
        data = new TheClassData(filename);
        tc = new TheClass(data);
    }
    virtual void TearDown() {
        delete tc;
        delete data;
    }

    TheClassData* data;
    TheClass* tc;
};

Now in the test simply use this overload to set up filename:

TEST_F(TheClassTest, MyTestCaseName)
{
    SetUp("my_filename_for_this_test_case");

    ...
}

The parameterless TearDown will automatically clean up when the test is complete.

Use the current class as a base class for your fixtures:

class TheClassTestBase : public ::testing::Test {
 protected:
  TheClassTestBase(std::string filename) : datafile(filename) {}
  ...
 };

For every specific filename - use derived fixture:

class TheClassTestForFooTxt : public TheClassTestBase {
protected:
    TheClassTestForFooTxt() : TheClassTestBase ("foo.txt") {}
};

However this is extra step needed for every set of parameters - so you can try to use templates or macros to get it done with less effort. Like:

template <typename ClassTestTag>
struct ClassTestParams
{
    static std::string filename;
};

template<typename  ClassTestTag>
class TheClassTest : public TheClassTestBase {
protected:
    TheClassTest() : TheClassTestBase (ClassTestParams<ClassTestTag>::filename) {}
};

Then - for every set of parameters - do that:

class FooTxtTag {};
template <> std::string ClassTestParams<FooTxtTag>::value = "foo.txt";
using TheClassTestForFooTxt = TheClassTest<FooTxtTag>;
TEST_F(TheClassTestForFooTxt, xxxx) {}

However - in your specific case - I would also try GoogleTest:type-parameterized-tests.

Another great way to deal with this is to just extend your fixture and in the extended class supply a new default constructor which calls through to the old one with the arguments you require. For example:

struct MySpecializedTestFixture : public GenericTestFixture
{
  MySpecializedTestFixture() : GenericTestFixture("a thing", "another thing") {}
};

TEST_F(MySpecializedTestFixture, FancyTest)
{
  // Use the thing environment and make some assertions.
}

For this specific case, I feel it is much easier to get rid of the test fixture altogether. The SetUp function can instead be replaced with a helper function that instantiates the class with the required file name. This permits the use of TEST instead of TEST_P or TEST_F. Now each test case is a standalone test which creates its own test class instances with the helper function or directly in the body of the test case.

For example:

using namespace testing;
TEST(FooClassTest, testCase1)
{
    FooClass fooInstance("File_name_for_testCase1.txt");
    /* The test case body*/
    delete fooInstance;
}

If you overload the SetUp method as suggested here, and you want to ensure that you remember to use the overloaded SetUp, you can use an assertion in the TearDown method.

class my_fixture : public ::testing::Test
{
protected:
    bool SETUP_HIT_FLAG = false;

    void SetUp(double parameter)
    {
        ...
        SETUP_HIT_FLAG = true;
    }

    void TearDown() override
    {
        assert(SETUP_HIT_FLAG && "You forgot to call SetUp with your parameter!");
    }
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!