【发布时间】:2011-07-22 12:24:32
【问题描述】:
假设我有课
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;
这避免了样板化和不必要的虚拟调度;但是现在我的整个代码库都在该死的头文件中,这使得隐藏源代码实现变得不可能(更不用说处理令人沮丧的模板编译错误和漫长的构建时间了)。
虚拟和模板这两种方法是进行正确单元测试的唯一方法吗?有没有更好的方法来进行正确的单元测试?
通过适当的单元测试,我的意思是每个单元测试只测试该单元引入的功能,而不测试该单元的依赖项。
【问题讨论】:
标签: c++ unit-testing mocking googletest