Specify constructor arguments for a Google test Fixture

末鹿安然 提交于 2019-12-06 20:10:50

问题


With Google test I want to specify a Test fixture for use in different test cases. The fixture shall allocate and deallocate objects of the class TheClass and its data management class TheClassData, where the data management class requires the name of a datafile.
For the different tests, the file name should vary.

I defined the following Fixture:

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

  std::string datafile;
  TheClassData* data;
  TheClass* tc;
};

Now, different tests should use the fixture with different file names. Imagine this as setting up a test environment.

The question: How can I specify the filename from a test, i.e. how to call a non-default constructor of a fixture?

I found things like ::testing::TestWithParam<T> and TEST_P, which doesn't help, as I don't want to run one test with different values, but different tests with one fixture.


回答1:


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.




回答2:


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.




回答3:


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.
}



回答4:


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;
}



回答5:


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!");
    }
};


来源:https://stackoverflow.com/questions/38207346/specify-constructor-arguments-for-a-google-test-fixture

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!