Specify constructor arguments for a Google test Fixture

22,673

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

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

Solution 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.
}
Share:
22,673
Gregor
Author by

Gregor

I'm doing software, math, and engineering related stuff.

Updated on December 22, 2021

Comments

  • Gregor
    Gregor over 2 years

    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.