如何在 Google Test (gtest) 中使用夹具成员值运行参数化测试?

Nik*_*ita 9 c++ unit-testing xunit googletest

我想要实现的是参数化测试 TEST_P(MyFixtureClass, DoStuff),我可以用它测试不同的值。虽然所说的值不应该是常量,就像那些通常传递给INSTANTIATE_TEST_CASE_P. 此外,我想使用其他夹具类中的值 - 理想情况下。

似乎没有任何东西,它涵盖了在创建参数化测试时使用字段而不是静态值。在官方文件似乎没有任何掩盖这一点-可悲的。


但是为了避免在这个问题中引入 XY 问题,这里是等效的伪代码:

参数化的夹具,MyFixture

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

    void SetUp() override
    {
        a = GetParam();
    }
};
Run Code Online (Sandbox Code Playgroud)

OtherFixture 看起来像这样:

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

    void SetUp() override
    {
        a = CalculateSomeFloat();
        b = CalculateSomeFloat();
        c = CalculateSomeFloat();
    }
};
Run Code Online (Sandbox Code Playgroud)

测试用例类似于:

// 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
}
Run Code Online (Sandbox Code Playgroud)

最后,我们将实例化参数化测试:

INSTANTIATE_TEST_CASE_P(MyFloatTesting, MyFixture, ::testing::Values(
    OtherFixture::a, OtherFixture::b, OtherFixture::c
));
Run Code Online (Sandbox Code Playgroud)

显然,这OtherFixture::a是不合适的,但它说明了我想在继承的夹具类(或任何与此相关的夹具类)中引用字段的位置。


那么有没有办法用gtest来实现这一点?我不一定需要使用参数化测试。简单地避免为不同的对象编写相同的测试对我来说很好。


任何建议都非常感谢!

Pio*_*ycz 13

我认为你需要使用::testing::Combine.

并将参数从 更改floatstd::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());
    }


};
Run Code Online (Sandbox Code Playgroud)

要定义参数集,请使用以下方法:

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));
Run Code Online (Sandbox Code Playgroud)

然后,您可以编写关于以下成员的通用测试OtherFixture

TEST_P(MyFixture, test)
{
    ASSERT_EQ(a, memberToTest());
}
Run Code Online (Sandbox Code Playgroud)

我还建议你PrintTofloat 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;

}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您会在失败的情况下收到很好的消息:

[失败] AllMembers/MyFixture.test/5,其中 GetParam() = (3.2, &OtherFixture::c)

与没有 PrintTo 的讨厌的、毫无意义的消息相比:

[失败] AllMembers/MyFixture.test/5,其中 GetParam() = (3.2, 4-byte object <10-00 00-00>)

  • 我没想到我可以使用函数指针,例如`float OtherFixture::*`。我非常感谢“PrintTo”的添加,感谢您付出更多努力。 (2认同)