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!
Test Fixtures A test fixture is a class that inherits from ::testing::Test and whose internal state is accessible to tests that use it.
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.
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>)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With