我正在编写一些单元测试。特别是我想测试一些私有方法。
到目前为止,我已经想出了使用。
#define private public
但我对此并不满意,因为从单元测试的角度来看,它会破坏所有封装。
您使用什么方法对私有方法进行单元测试。
我正在编写一些单元测试。特别是我想测试一些私有方法。
到目前为止,我已经想出了使用。
#define private public
但我对此并不满意,因为从单元测试的角度来看,它会破坏所有封装。
您使用什么方法对私有方法进行单元测试。
而不是#define
你在问题中提到的讨厌的黑客,一个更干净的机制是让测试成为被测类的朋友。这允许测试代码(并且只是测试代码)访问私有数据,同时保护它们免受其他任何事情的影响。
但是,最好通过公共接口进行测试。如果你的 X 类在私有成员函数中有很多代码,那么可能值得提取一个新的 Y 类,它被 X 类的实现使用。然后可以通过它的公共接口测试这个新的 Y 类,而不会暴露它的用于 X 类的客户。
如果您使用的是 Google Test,则可以使用FRIEND_TEST轻松地将您的测试夹具声明为被测类的朋友。
而且您知道,如果测试私有函数确实像其他一些答案所说的那样糟糕,那么它可能不会内置到 Google Test 中。
您可以在这个答案中阅读更多关于测试私有函数是好是坏的信息。
如果方法足够复杂,需要单独进行测试,则将它们重构为自己的类并通过其公共接口进行测试。然后在原始类中私下使用它们。
使测试类成为原始类的朋友。这个朋友声明将在#define UNIT_TEST
标志内。
class To_test_class {
#ifdef UNIT_TEST
friend test_class;
#endif
}
现在对于您的单元测试,您将使用 flag 编译代码-DUNIT_TEST
。这样你就可以测试私有函数了。
现在您的单元测试代码将不会被推送到生产环境中,因为UNIT_TEST
flag 将为 false。因此,代码仍然是安全的。
此外,您不需要任何特殊的库来进行单元测试。
我知道这是一个较老的问题,但似乎没有人分享我喜欢的相对好的方法,所以这里是:
将您要测试的方法从 更改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);
}
}
当然,您必须更新单元测试才能在派生类而不是基类上运行测试,但之后,对基类所做的任何更改都会自动反映在“测试”类中。
几个小时后,这就是我决定为那些想要测试他们的私人功能的人提供的最佳解决方案。这是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
或添加朋友到您的班级!
定义黑客是一个可怕的想法。当你去编译它时,用预处理器随意重写你的代码是不明智的。
现在正如一些人已经提到的那样,您是否应该测试私有方法是有争议的。但这不包括您故意隐藏构造函数以将实例化限制在某些范围内的情况,或其他一些更深奥的情况。
此外,您不能为命名空间加好友,并且“友谊”不会在 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
您可以将夹具设为好友,并让它实例化您在单元测试功能中使用的所有实例,将它们声明为夹具的静态并具有模块范围。如果您使用的是命名空间,请不要担心,您可以在命名空间内声明您的固定装置,在命名空间之外声明您的测试用例,然后使用范围解析运算符获取静态成员。
该BOOST_FIXTURE_TEST_CASE
宏将负责为您实例化和拆除您的夹具。
我认为私有方法不需要单元测试用例。
如果方法是私有的,则只能在该类中使用。如果您已经使用此私有方法测试了所有公共方法,则无需单独测试,因为它仅以多种方式使用。