Home > Software engineering >  Use arbitrary classes as parameter for parametrized tests in googletest
Use arbitrary classes as parameter for parametrized tests in googletest

Time:02-18

I have some repetive tests where the input of the tests needs to be created uniquely in a non-repetive way. Imagine 2 tests like this:

struct ComplexInput{};

ComplexInput CreateA();
ComplexInput CreateB();

bool FunctionUnderTest(ComplexInput& input);

TEST(TestCase, TestWithA)
{
    auto input = CreateA();
    auto ret = FunctionUnderTest(input);
    EXPECT_TRUE(ret);
}

TEST(TestCase, TestWithB)
{
    auto input = CreateB();
    auto ret = FunctionUnderTest(input);
    EXPECT_TRUE(ret);
}

Is there any way to parametrize the tests to specify the function which should be called e.g. with templates? The only solution I can think of is using an enum to specify the data and using a function which returns the correct data based on the enum type, but this feels like a hack:

struct ComplexInput{};

ComplexInput CreateA();
ComplexInput CreateB();

bool FunctionUnderTest(ComplexInput& input);

class enum InputChoice
{
    A, 
    B
};

ComplexInput GetComplexInput(InputChoice c)
{
    switch(c)
    {
        case A:
        return CreateA();
        case B:
        return CreateB();
    }
}

class ParamTest : public ::testing::TestWithParam<InputChoice>{};

TEST_P(ParamTest, Test)
{
    InputChoice c = GetParam();
    auto input = GetComplexInput(c);
    auto ret = FunctionUnderTest(input);
    EXPECT_TRUE(ret);
}

INSTANTIATE_TEST_CASE_P
(
    Tests,
    ParamTest,
    ::testing::Values
    (
        InputChoice::A,
        InputChoice::B
        // maybe this could also be automated?
    )
);

Please keep in mind that this code is only to demonstrate the scenario and it could be that it does not compile.

CodePudding user response:

You can store function pointers and pass them to parameterized tests, as long as they have the same type (i.e., same parameters and return type)

See it online

struct ComplexInput{};

ComplexInput CreateA();
ComplexInput CreateB();

bool FunctionUnderTest(ComplexInput& input);

class ParamTest : public ::testing::TestWithParam<ComplexInput(*)()>{};

TEST_P(TestCase, TestWithA)
{
    auto uutCreator = GetParam();
    auto input = uutCreator();
    auto ret = FunctionUnderTest(input);
    EXPECT_TRUE(ret);
}

INSTANTIATE_TEST_SUITE_P(MyParamTest, ParamTest, 
                         ::testing::Values(CreateA, CreateB));

If the functions do not have the same signature in reality, they you need to consider if you can use some wrappers to get them to the same signature or if it's better to just have separate (non-parameterized) tests.

Important note: This will work for lambdas with empty capture list, free functions or static member functions.
For lambdas that have a non-empty capture list you must use std::function<ComplexInput()> instead of ComplexInput(*)().
Non-static member functions will have a bit more involved syntax.

  • Related