关于c ++:私有方法的单元测试

Unit testing of private methods

本问题已经有最佳答案,请猛点这里访问。

我正在写一些单元测试。特别是我想测试一些私有方法。

到目前为止,我已经想出了使用。

1
#define private public

但我对此并不满意,因为从单元测试的角度来看,它会破坏所有的封装。

您使用什么方法对私有方法进行单元测试。


与您在问题中提到的讨厌的#define黑客攻击不同,更干净的机制是让测试成为被测试类的朋友。这允许测试代码(和测试代码)访问私有,同时保护他们不受其他任何影响。

但是,最好通过公共接口进行测试。如果您的类X在私有成员函数中有很多代码,那么它可能值得提取一个新的类Y,该类Y由类X的实现使用。然后可以通过它的公共接口测试这个新的类Y,而不必向类X的客户机公开它的使用。


如果您使用的是Google测试,那么您可以使用friend_测试轻松地将您的测试夹具声明为被测试类的朋友。

你知道,如果测试私有函数像其他一些答案所说的那样毫无疑问是糟糕的,那么它可能不会被内置到谷歌测试中。

在这个答案中,您可以阅读更多关于测试私有函数是好还是坏的信息。


如果这些方法足够复杂,可以单独进行测试,那么将它们重构为自己的类,并通过它们的公共接口进行测试。然后在原始类中私下使用它们。


使测试类成为原始类的朋友。此友元声明将位于#define UNIT_TEST标志内。

1
2
3
4
5
class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

现在,对于单元测试,您将使用标志-DUNIT_TEST编译代码。这样您就可以测试私有函数了。

现在,您的单元测试代码不会被推送到生产环境中,因为UNIT_TEST标志将是错误的。因此,代码仍然是安全的。

此外,您不需要任何特殊的库来进行单元测试。


我知道这是一个古老的问题,但似乎没有人分享过我喜欢的相对好的方法,所以这里是:

将您希望测试的方法从private更改为protected。对于其他类,方法仍然是private,但是现在您可以从您的基类派生一个"测试"类,它公开了您想要测试的私有功能。

下面是一个最小的例子:

1
2
3
4
5
6
7
8
9
10
11
class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

当然,您必须更新单元测试才能在派生类而不是基类上运行测试,但是在这之后,对基类所做的任何更改都将自动反映在"测试"类中。


定义黑客是一个可怕的想法。当你去编译代码时,用预处理器随意地重新编写代码是不明智的。

现在正如一些人已经提到的,您是否应该测试私有方法还存在争议。但这并不包括故意隐藏构造函数以将Instantiaton限制在特定范围内的情况,或者其他一些更为深奥的情况。

而且,你不能在命名空间中建立朋友关系,而"友谊"不是在C++中继承的,所以取决于你的单元测试框架,你可能会遇到麻烦。幸运的是,如果您使用的是boost.test,那么这个问题的优雅解决方案是以fixture的形式出现的。

http://www.boost.org/doc/libs/1__0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

您可以使这个fixture成为朋友,并让它实例化您在单元测试函数中使用的所有实例,将它们声明为fixture的静态实例和模块范围。如果您使用的是名称空间,不用担心,您可以只声明名称空间内的fixture和名称空间外的测试用例,然后使用scope resolution操作符来获取静态成员。

BOOST_FIXTURE_TEST_CASE宏将负责为您实例化和分解夹具。


很多小时后,我决定这是对那些想要测试其私有功能的人最好的解决方案。这是Max Deliso和Milo的答案组合?.

如果您使用的是Boost::Unit测试,那么有一个简单而优雅的解决方案。

  • 在课堂上使用protected而不是private

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* MyClass.hpp */

    class MyClass {

    protected:
        int test() {
            return 1;
        }
    };
  • 创建设备:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* TestMyClass.cpp */

    class F : public MyClass {};


    BOOST_FIXTURE_TEST_SUITE(SomeTests, F)

    // use any protected methods inside your tests
    BOOST_AUTO_TEST_CASE(init_test)
    {
        BOOST_CHECK_EQUAL( test(), 1 );
    }
    BOOST_AUTO_TEST_SUITE_END()
  • 这样,您就可以自由地使用任何MyClass功能,而无需#define private public或向您的班级添加朋友!


    我认为私有方法不需要单元测试用例。

    如果方法是私有的,则只能在该类中使用。如果您已经使用这个私有方法测试了所有的公共方法,那么就不需要单独测试它,因为它只在这些许多方面使用。