如何使 google-test 课程与我的课程成为朋友?

问题描述 投票:0回答:5

我听说可以将 google-test TestCase 类的朋友启用到我的类中,从而使测试能够访问我的私有/受保护的成员。

如何实现?

c++ friend googletest
5个回答
62
投票

试试这个(直接来自 Google 测试文档...):

FRIEND_TEST(TestCaseName, TestName);

例如:

// foo.h
#include <gtest/gtest_prod.h>

// Defines FRIEND_TEST.
class Foo {
  ...
 private:
  FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
  int Bar(void* x);
};

// foo_test.cc
...
TEST(FooTest, BarReturnsZeroOnNull) {
  Foo foo;
  EXPECT_EQ(0, foo.Bar(NULL));
  // Uses Foo's private member Bar().
}

43
投票

我知道这已经很旧了,但我今天正在寻找相同的答案。 “gtest_prod.h”只是引入了一个简单的宏来引用测试类。

#define FRIEND_TEST(test_case_name, test_name)\
friend class test_case_name##_##test_name##_Test

所以

FRIEND_TEST(FooTest, BarReturnsZeroOnNull);
相当于:

friend class FooTest_BarReturnsZeroOnNull_Test;

这是有效的,因为每个测试都是它自己的类,如前面的答案中提到的。


11
投票

更好的策略是在单元测试中不允许进行朋友测试。

允许好友测试访问私有成员将导致代码库难以维护。每当重构组件的内部实现细节时就会中断的测试不是您想要的。如果付出额外的努力来获得可以通过其公共接口测试组件的设计,那么您将获得只需要在组件的公共接口更新时就更新的测试。

依赖于

gtest/gtest_prod.h
的测试应该被视为设计不佳的标志。


10
投票

当您的测试类和您的测试类位于不同的命名空间中时(例如您的测试位于全局命名空间中),您可能需要前向声明您的测试类并在

FRIEND_TEST
中添加您的命名空间前缀:

// foo.h
#include <gtest/gtest_prod.h>

// forward-declaration of test class
class FooTest_BarReturnsZeroOnNull_Test; 

// Defines FRIEND_TEST.
class my_namespace::Foo {
    ...
private:
    // Specify the global namespace (`::`) in the `FRIEND_TEST()` usage
    FRIEND_TEST(::FooTest, BarReturnsZeroOnNull);
    int Bar(void* x);
};

// forward-declaration of this namespace from foo_test.cc
using namespace my_namespace;

...
TEST(FooTest, BarReturnsZeroOnNull) {
    Foo foo;
    EXPECT_EQ(0, foo.Bar(NULL));
    // Uses Foo's private member Bar().
}

我知道朋友单元测试(或一般 C++ 中的友好性)和白盒测试是一个有争议的主题,但是当您研究复杂的科学算法时,您需要测试和验证其中的每一步,但是您不想暴露在公共(甚至受保护)接口中,朋友测试在我看来是一个简单而实用的解决方案,特别是在测试驱动的开发方法中。如果使用友好性或白盒测试违背了自己的宗教信仰,那么以后总是可以重构代码(或完全删除白盒测试)。


0
投票

如果您不想使用

FRIEND_TEST
单独列出每个测试用例,另一种选择是定义一个测试夹具类,然后改为友元:

class Foo
{
    ...
private:
    friend class FooTest;
};
...
class FooTest : public ::testing::Test
{
protected:
    int AccessPrivateFooThing(Foo& foo) { ... }    
    ...
};
...
TEST_F(FooTest, PrivateThing)
{
   ...
   int result = AccessPrivateFooThing(foo);
   ...
}

然而,需要注意的是,只有在测试装置本身定义的方法才能访问

Foo
的私有成员;测试本身不会。您必须在需要访问的固定装置中定义访问器、保镖或其他辅助方法。与其他一些解决方案相比,这需要更多的样板,但也更明确,这有望阻止过多地触及内部。

如果您遇到命名空间问题,只需确保测试装置与相关类位于同一命名空间中即可;无论如何,这是一个很好的做法。

仍然强烈鼓励在合理可行的情况下仅测试公共成员,尽管我确实同意有时这样做更有意义。

© www.soinside.com 2019 - 2024. All rights reserved.