测与不测之争
关于类的私有成员(数据和方法),要不要进行单元测试之争,尚没有统一的结论;(关于这一争论,可以参考http://stackoverflow.com/questions/9202862/is-unit-testing-private-methods-a-good-practice)
有人认为测试私有成员也是一个好的实践,原因嘛,就是没有原因,你本来就应该测你的所有代码;也有人说,类的私有成员根本就不应该测试,单元测试只需要测试对外暴露的接口即可;如果你有对私有成员进行测试的需求,那说明你的设计做的不够好;他们的建议是:将这些私有的方法,重新组织到一个Impl类里面,然后公开这些方法;在原有的类里面,再来使用Impl类暴露的方法。
其实我赞成“应该测试”这样一种说法;原因如下:
- 一个类,除了对外的接口之外,本身就封装、隐藏了很多实现的细节,这个OO的特性之一。(也有观点认为,封装是TDD的天敌:http://jasonmbaker.wordpress.com/2009/01/08/enemies-of-test-driven-development-part-i-encapsulation/)
- 如果将所有的private方法重新组织到一个Impl类里面,然后公开这些方法,事实上就暴露了实现的细节;你怎么去保证这些Impl类不会被直接使用呢?
- 即使你的Impl类,总应该有一些private的数据成员吧,也就是类的状态,这些状态值,又如何来进行确认呢?例如类内部有一个计数器,它仅仅在内部使用,因此不需要定义个getter,public方法调用后,这个计数器的状态是否正确?如果不对这些private成员做测试,如何确认他们的正确性呢?
因此,在需要对private进行测试的时候,就测吧。
如何测试私有成员
不过,成员既然是private的,也就是不太愿意让外面的家伙看到的家丑,又怎么进行测试呢,主要由这样几种方法:
- 最简单的,使用#define private public粗暴地将private变成public,不过这要放在#include头文件之前。如:
#define private public
#include “myclass.h”
- 使用friend。这个会相对友好一点,但是却需要修改原有的代码。
- 使用一些旁门左道,例如:
- a. 在知道类对象内存布局的情况下,通过地址偏移直接操作地址访问类的数据成员;
- b. 创建一个具有完全相同内存布局的Dummy类,然后进行强制转换并访问数据。例如
class Data
{
public:
int GetValue() { return m_value; };
private:
int m_value;
};
class DummyData
{
public:
int GetValue() { return m_value; };
public:
int m_value;
};
void AccessPrivateMember()
{
Data data; /// Data::m_value is not accessible
// Here comes the ugly hack
DummyData* pDummy = reinterpret_cast<DummyData*>(&data);
pDummy->m_value = 17;
// Print out the value
std::cout << data.GetValue() << std::endl;
}
方法一最简单也最粗暴;方法二文雅点,但要修改原代码;方法三系出非名门,且只对数据成员有效;