假设你有一堆相互调用的函数。你想独立地测试它们中的每一个。例如。你应该能够在没有Bar正确甚至实现的情况下测试Foo。一种解决方案是将这些函数转换为虚拟方法(如果您不使用C ++,则只需常规方法)。 E.g。
class K {
public:
virtual int Foo();
virtual int Bar(); // called by Foo
// No member variables.
};
现在,您可以在测试中执行此操作:
// You could use googlemock instead of this.
class KFoo : public K {
public:
virtual int Bar() {
return 42;
}
};
// googletest
TEST(K, Foo) {
std::unique_ptr<K> k(new KFoo);
assert(k->Foo() == 7); // Bar gets called, and returns 42.
}
这有点奇怪,但有几个原因:
new K
才能拨打任何电话。这是个好主意吗?这已经有了名字吗?显然,虚拟减慢了速度,但是IIUC,除非你进行大量的呼叫,否则性能影响很小(而且你知道他们对过早优化的看法)。我对这将如何影响可维护性,可测试性等更感兴趣。
答案 0 :(得分:1)
我在C ++中无法确定,但我有C#(完整OOP)的经验。
我认为在C#中,您提到的设计是抽象类/继承。如果我没弄错的话,你在C ++中的设计将在C#中变成这样:
public class K{
public virtual int Foo(){
return Bar();
}
public virtual int Bar(){
// actual code
}
}
public class KFoo : K{
public override int Bar(){
return 42;
}
}
这种设计是OOP的基础,所以它没有害处。但是,随着更多的继承被添加(K2继承K,K3继承K2等),它将变得更加复杂。作为附加信息,您可以阅读此answer解释我的观点,为什么有时基于继承/类的方法有时不像您想象的那样模块化。
恕我直言,如果你注入“服务”类而不是定义继承,它将是模块化的,它被称为组合而不是继承。
public class KBarService : IKBarService{
public int Bar(){
// actual code
}
}
public class KBarServiceMock : IKBarService{
public int Bar(){
return 42;
}
}
public class K{
public K(IKBarService service){
this.service = service;
}
IKBarService service;
public int Foo(){
return Bar();
}
public int Bar(){
return service.Bar();
}
}
您可以对Foo()
执行相同的操作。使用此设计,您可以在其他类中重用KBarService
,即使该类不是派生类形式K.