0

假设您有一堆相互调用的函数。您想单独测试它们中的每一个。例如,您应该能够在 Bar 不正确甚至没有实现的情况下测试 Foo。一种解决方案是将这些函数转换为虚拟方法(或者如果您不使用 C++,则只是常规方法)。例如

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.
}

这很奇怪,但有几个原因:

  1. K 没有成员变量;它是“无国籍”的。
  2. 你需要new K为了调用任何东西。

这是一个好主意吗?这已经有名字了吗?显然,虚拟会减慢速度,但是 IIUC,除非您进行大量调用,否则性能影响很小(而且您知道他们所说的过早优化)。我对这将如何影响可维护性、可测试性等更感兴趣。

4

1 回答 1

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;
    }
}

这种设计是面向对象编程的基础,所以它是无害的。但是,随着更多继承的添加(K2继承K,K3继承K2等),它会变得更加复杂。作为附加信息,您可以阅读此答案,解释我的观点,即为什么有时基于继承/类的方法有时不像您想象的那样模块化。

恕我直言,如果您注入“服务”类而不是定义继承,它将是模块化的,它被称为组合而不是继承。

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。

于 2013-07-15T01:58:08.877 回答