class Inner {
public:
void doSomething();
};
class Outer {
public:
Outer(Inner *inner); // Dependency injection.
void callInner();
};
正确的单元测试说我应该有测试为Inner
。然后,我应该对Outer
进行测试,该测试不使用真实的Inner
而是使用MockInner
,这样我将对仅添加Outer
的功能执行单元测试,而不是完整的堆栈Outer
/Inner
。
要做到这一点,Googletest似乎暗示转向Inner
成纯抽象类(接口)是这样的:
// Introduced merely for the sake of unit-testing.
struct InnerInterface {
void doSomething() = 0;
};
// Used in production.
class Inner : public InnerInterface {
public:
/* override */ void doSomething();
};
// Used in unit-tests.
class MockInner : public InnerInterface {
public:
/* override */ void doSomething();
};
class Outer {
public:
Outer(Inner *inner); // Dependency injection.
void callInner();
};
因此,在生产代码,我会用Outer(new Inner)
;而在测试中,Outer(new MockInner)
。
好的。理论上看起来不错,但是当我在整个代码中开始使用这个想法时,我发现自己为每一个疯狂的课程创建了一个纯粹的抽象类。即使您可以忽略由于不必要的虚拟调度而导致的轻微运行时间性能下降,这也是很多锅炉式输入。
另一种方法是使用模板,如下:
class Inner {
public:
void doSomething();
};
class MockInner {
public:
void doSomething();
};
template<class I>
class Outer {
public:
Outer(I *inner);
void callInner();
};
// In production, use
Outer<Inner> obj;
// In test, use
Outer<MockInner> test_obj;
这避免了锅炉电镀和不必要的虚拟调度;但是现在我的整个代码库都在怪异的头文件中,这使得无法隐藏源实现(更不用说处理令人沮丧的模板编译错误和长的构建时间)。
这两种方法,虚拟和模板是进行适当单元测试的唯一方法吗?有更好的方法来做适当的单元测试吗?
通过适当的单元测试,我的意思是每个单元测试测试只能由单位推出的功能,但不是单位的依赖性也。
我个人更喜欢工作单元测试和简单,干净,可维护的设计,以坚持单元测试纯粹主义者设定的一些理想。 我喜欢这个回应---保持事物的实用性。 – kirakun 2011-03-24 22:46:38