假设我有课
class Inner {
public:
void doSomething();
};
class Outer {
public:
Outer(Inner *inner); // Dependency injection.
void callInner();
};
正确的单元测试表明我应该对 Inner
进行测试。然后,我应该对 Outer
进行测试,它不使用真正的 Inner
而是使用 MockInner
以便我在仅由 Outer
而不是完整堆栈 Outer
/Inner
添加的功能。
为此,Googletest似乎建议将 Inner
变成这样的纯抽象类(接口(interface)):
// 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;
这避免了样板化和不必要的虚拟调度;但是现在我的整个代码库都在该死的头文件中,这使得隐藏源代码实现变得不可能(更不用说处理令人沮丧的模板编译错误和漫长的构建时间了)。
虚拟和模板这两种方法是进行正确单元测试的唯一方法吗?有没有更好的方法来进行正确的单元测试?
通过适当的单元测试,我的意思是每个单元测试只测试该单元引入的功能,而不测试该单元的依赖项。
最佳答案
我认为您必须在实践中模拟出您测试类的每个依赖项。如果创建、使用或感知它很复杂,那么是的。此外,如果它直接依赖于一些不需要的外部资源,例如数据库、网络或文件系统。
但如果这些都不是问题,IMO 可以直接使用它的一个实例。由于您已经对其进行了单元测试,因此您可以合理地确定它按预期工作并且不会干扰更高级别的单元测试。
我个人更喜欢工作单元测试和简单、干净、可维护的设计,而不是坚持单元测试纯粹主义者的一些理想设置。
each unit-test tests only the functionalities introduced by that unit but not the unit's dependencies also.
使用功能和测试功能是两件截然不同的事情。
关于c++ - C++ 中的模拟对象是否总是需要虚拟方法或模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5426091/