在我看来,测试一个类的私有成员/方法的需求是一种代码异味,但我认为在C++中这是可行的。
举个例子,假设你有一个Dog类,除了公共构造函数外,其余都是私有成员/方法:
#include <iostream>
#include <string>
using namespace std;
class Dog {
public:
Dog(string name) { this->name = name; };
private:
string name;
string bark() { return name + ": Woof!"; };
static string Species;
static int Legs() { return 4; };
};
string Dog::Species = "Canis familiaris";
现在,由于某种原因,您想测试私有内容。您可以使用
privablic来实现这一点。
同时,将所需的实现与
privablic.h命名的头文件一起包含,如下所示:
然后根据任何实例成员的类型映射一些存根。
struct Dog_name { typedef string (Dog::*type); };
template class private_member<Dog_name, &Dog::name>;
...和实例方法;
struct Dog_bark { typedef string (Dog::*type)(); };
template class private_method<Dog_bark, &Dog::bark>;
对所有静态实例成员执行相同的操作
struct Dog_Species { typedef string *type; };
template class private_member<Dog_Species, &Dog::Species>;
...和静态实例方法。
struct Dog_Legs { typedef int (*type)(); };
template class private_method<Dog_Legs, &Dog::Legs>;
现在你可以测试它们全部:
#include <assert.h>
int main()
{
string name = "Fido";
Dog fido = Dog(name);
string fido_name = fido.*member<Dog_name>::value;
assert (fido_name == name);
string fido_bark = (&fido->*func<Dog_bark>::ptr)();
string bark = "Fido: Woof!";
assert( fido_bark == bark);
string fido_species = *member<Dog_Species>::value;
string species = "Canis familiaris";
assert(fido_species == species);
int fido_legs = (*func<Dog_Legs>::ptr)();
int legs = 4;
assert(fido_legs == legs);
printf("all assertions passed\n");
};
输出:
$ ./main
all assertions passed
您可以查看test_dog.cpp和dog.hpp的源代码。
免责声明:感谢其他聪明人的见解,我已经组装了上述“库”,能够访问给定C++类的私有成员和方法,而不会改变其定义或行为。为使其正常工作,需要知道并包含类的实现(显然)。
注意:我根据评论员建议修改了此答案的内容。
OtherClass
调用另一个类中的方法,该方法又调用另一个类中的方法,以此类推。我认为依赖其他类的影响是有风险的(即:你不再测试单元,而是同时测试多个单元)。@André:感谢指引,但阅读后我和@Konrad持相同看法:我不喜欢将私有方法公开的想法。最多,可以使用条件编译(使用某些答案中提到的技巧)将它们公开。 - Jir