我正在编写一些单元测试。 特别是我想测试一些私有方法。
到目前为止,我已经提出了使用。
#define private public
但我对此并不满意,因为它会从单元测试的角度破坏所有封装。
您使用哪些方法对私有方法进行单元测试。
答案 0 :(得分:72)
而不是你在问题中提到的令人讨厌的#define
黑客,更清晰的机制是使测试成为被测试类的朋友。这允许测试代码(以及测试代码)访问私有部分,同时保护它们免受其他一切的侵害。
但是,最好通过公共接口进行测试。如果你的类X在私有成员函数中有很多代码,那么可能值得提取一个由类X的实现使用的新类Y.然后可以通过它的公共接口测试这个新的类Y,而不暴露它用于X类的客户。
答案 1 :(得分:59)
如果您使用的是Google测试,则可以使用FRIEND_TEST轻松将测试夹具声明为受测试类的朋友。
而且你知道,如果像其他一些答案所说的那样测试私有函数是非常糟糕的,那么它可能不会被内置到Google Test中。
您可以阅读有关何时测试私有函数是好还是坏in this answer的更多信息。
答案 2 :(得分:57)
如果方法足够复杂以保证单独进行测试,则将它们重构为自己的类,并通过其公共接口进行测试。然后在原始课堂中私下使用它们。
答案 3 :(得分:29)
使测试类成为原始类的朋友。这个朋友声明将在#define UNIT_TEST
标志内。
class To_test_class {
#ifdef UNIT_TEST
friend test_class;
#endif
}
现在进行单元测试,您将使用标记-DUNIT_TEST
编译代码。这样您就可以测试私有函数了。
现在您的单元测试代码不会被推送到生产环境中,因为UNIT_TEST
标志将为false。因此代码仍然是安全的。
此外,您不需要任何特殊的库来进行单元测试。
答案 4 :(得分:12)
我知道这是一个较老的问题,但似乎没有人分享我喜欢的相对好的方法,所以在这里:
将您要测试的方法从private
更改为protected
。对于其他类,该方法仍然是private
,但现在您可以推导出"测试"来自您的基类的类,它公开您要测试的私有功能。
这是一个最小的例子:
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);
}
}
当然,您必须更新单元测试以在派生类而不是基类上运行测试,但在此之后,对基类所做的任何更改都将自动反映在"测试&#中34;类。
答案 5 :(得分:5)
定义黑客是一个可怕的想法。在编译它时,任意用预处理器重写代码是不明智的。
现在有几个人已经提到过,你是否应该测试私有方法是有争议的。但是这并不包括你故意隐藏构造函数来限制实例化到某些范围的情况,或者其他一些更深奥的情况。
此外,你不能成为命名空间的朋友,并且“友谊”不会在C ++中继承,因此根据您的单元测试框架,您可能遇到麻烦。幸运的是,如果你正在使用Boost.Test,那么就可以通过Fixtures的形式优雅地解决这个问题。
http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html
您可以对夹具进行操作,并让它实例化您在单元测试功能中使用的所有实例,将它们声明为夹具的静态实例和模块范围。如果您正在使用命名空间,请不要担心,您可以在命名空间中声明fixture,并在命名空间之外声明测试用例,然后使用范围解析运算符来获取静态成员。
BOOST_FIXTURE_TEST_CASE
宏将负责为您实例化和拆除您的灯具。
答案 6 :(得分:4)
经过几个小时后,我决定成为那些想要测试私人功能的人的最佳解决方案。这是Max DeLiso和Miloš的答案组合。
如果您使用 boost :: unit-test ,那么这是一个简单而优雅的解决方案。
在您的课程中使用protected
代替private
/* MyClass.hpp */
class MyClass {
protected:
int test() {
return 1;
}
};
创建灯具:
/* 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
或将朋友添加到您的课程中!
答案 7 :(得分:1)
我不认为私有方法需要单元测试用例。
如果某个方法是私有的,则只能在该类中使用。如果您使用此私有方法测试了所有公共方法,则无需单独测试它,因为它仅以多种方式使用。