Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run Parameterized Tests with fixture member values in Google Test (gtest)?

What I want to achieve is a Paramaterized Test TEST_P(MyFixtureClass, DoStuff), with which I can test different values. Though said values shouldn't be constants, like those typically passed to INSTANTIATE_TEST_CASE_P. Moreover, I would want to use the values within some other fixture class - ideally.

There doesn't seem to be anything out there, which covers using fields instead of static values when creating parameterized tests. The official documentation doesn't seem to cover this either - sadly.


But to avoid introducing the XY-problem in this question, here is the equivalent pseudo code:

The parameterized fixture, MyFixture:

struct MyFixture : OtherFixture, ::testing::WithParamInterface<float>
{
    float a;

    void SetUp() override
    {
        a = GetParam();
    }
};

OtherFixture would look like this:

struct OtherFixture : testing::Test
{
    float a;
    float b;
    float c;

    void SetUp() override
    {
        a = CalculateSomeFloat();
        b = CalculateSomeFloat();
        c = CalculateSomeFloat();
    }
};

The test case would be something like:

// This here is the key aspect.
// Basically, I do not want to write a bunch of tests for a, b and c.
// Rather, I'd just test all 3 with this one.
TEST_P(MyFixture, DoStuff)
{
    ...bunch of tests
}

And lastly, we would instantiate the parameterized tests:

INSTANTIATE_TEST_CASE_P(MyFloatTesting, MyFixture, ::testing::Values(
    OtherFixture::a, OtherFixture::b, OtherFixture::c
));

Obviously, OtherFixture::a is inappropriate, but it illustrates where I would want to refer to a field, within a inherited fixture class (or any fixture class for that matter).


So is there any way to achieve this with gtest? I do not necessarily need to use parameterized tests. Simply avoiding having to write the same tests, for different objects is fine by me.


Any suggestions are much appreciated!

like image 930
Nikita Avatar asked Jan 08 '17 05:01

Nikita


People also ask

What is test fixture in Google Test?

Test Fixtures A test fixture is a class that inherits from ::testing::Test and whose internal state is accessible to tests that use it.

What is Test_p?

TEST_P() is useful when you want to write tests with a parameter. Instead of writing multiple tests with different values of the parameter, you can write one test using TEST_P() which uses GetParam() and can be instantiated using INSTANTIATE_TEST_SUITE_P() . Example test. Follow this answer to receive notifications.


1 Answers

I think you need to use ::testing::Combine.

And change the parameters from float to std::tuple<float, float OtherFixture::*>.

using OtherFixtureMemberAndValue = std::tuple<float, float OtherFixture::*>;

struct MyFixture : OtherFixture, ::testing::WithParamInterface<OtherFixtureMemberAndValue>
{
    float a = std::get<0>(GetParam());
    auto& memberToTest()
    {
        return this->*std::get<1>(GetParam());
    }


};

To define set of parameters use this approach:

const auto membersToTest = testing::Values(
     &OtherFixture::a, 
     &OtherFixture::b, 
     &OtherFixture::c
);

const auto floatValuesToTest = testing::Values(
    2.1, 
    3.2
    //  ... 
 );

INSTANTIATE_TEST_CASE_P(AllMembers,
                        MyFixture,
                        testing::Combine(floatValuesToTest, membersToTest));

Then you can write your tests generic with respect to members of OtherFixture:

TEST_P(MyFixture, test)
{
    ASSERT_EQ(a, memberToTest());
}

I would also advice that you wrote PrintTo for float OtherFixture::*:

void PrintTo(float OtherFixture::*member, std::ostream* os)
{
    if (member == &OtherFixture::a)
        *os << "&OtherFixture::a";
    else if (member == &OtherFixture::b)
        *os << "&OtherFixture::b";
    else if (member == &OtherFixture::c)
        *os << "&OtherFixture::c";
    else
        *os << "&OtherFixture::? = " << member;

}

In this way you get nice message in case of failure:

[ FAILED ] AllMembers/MyFixture.test/5, where GetParam() = (3.2, &OtherFixture::c)

comparing to nasty, meaningless message w/o PrintTo:

[ FAILED ] AllMembers/MyFixture.test/5, where GetParam() = (3.2, 4-byte object <10-00 00-00>)

like image 59
PiotrNycz Avatar answered Oct 21 '22 23:10

PiotrNycz