C++ 在C++;是否始终需要虚拟方法或模板?

C++ 在C++;是否始终需要虚拟方法或模板?,c++,unit-testing,mocking,googletest,C++,Unit Testing,Mocking,Googletest,假设我有课 class Inner { public: void doSomething(); }; class Outer { public: Outer(Inner *inner); // Dependency injection. void callInner(); }; 正确的单元测试表明我应该对内部进行测试。然后,我应该对外部进行测试,该测试使用的不是真正的内部,而是模拟内部,这样我就可以对由外部添加的功能执行单元测试,而不是整个堆栈外部/内部

假设我有课

class Inner {
  public:
    void doSomething();
};

class Outer {
  public:
    Outer(Inner *inner);  // Dependency injection.

    void callInner();
};
正确的单元测试表明我应该对
内部进行测试。然后,我应该对
外部
进行测试,该测试使用的不是真正的
内部
,而是
模拟内部
,这样我就可以对由
外部
添加的功能执行单元测试,而不是整个堆栈
外部
/
内部

为此,似乎建议将
内部
转换为纯抽象类(接口),如下所示:

// 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();
};
因此,在生产代码中,我将使用
外部(新内部)
;在测试中,
外部(新模拟内部)

嗯。理论上看起来不错,但当我开始在整个代码中使用这个想法时,我发现自己为每个奇怪的类创建了一个纯粹的抽象类。即使您可以忽略由于不必要的虚拟调度而导致的运行时性能的轻微降低,也需要大量的锅炉板类型

另一种方法是使用以下模板:

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;
类内部{
公众:
无效剂量();
};
类模拟内部{
公众:
无效剂量();
};
模板
类外部{
公众:
外部(I*内部);
void calliner();
};
//在生产、使用中
外obj;
//在测试中,使用
外部测试_obj;
这避免了锅炉电镀和不必要的虚拟调度;但是现在我的整个代码库都在奇怪的头文件中,这使得隐藏源代码实现变得不可能(更不用说处理令人沮丧的模板编译错误和漫长的构建时间了)

虚拟和模板这两种方法是进行正确单元测试的唯一方法吗?有没有更好的方法来进行适当的单元测试

通过适当的单元测试,我的意思是,每个单元测试只测试该单元引入的功能,而不测试单元的依赖关系,而且

我认为在实践中不必模拟测试类的所有依赖关系。如果它是复杂的创造,使用或感觉通过,那么是的。另外,如果它直接依赖于一些不需要的外部资源,例如数据库、网络或文件系统

但如果这些都不是问题,IMO可以直接使用它的一个实例。由于您已经对它进行了单元测试,所以可以合理地确保它按预期工作,并且不会干扰更高级别的单元测试


我个人更喜欢工作单元测试和简单、干净、可维护的设计,而不是遵循单元测试纯粹主义者的一些理想设置

每个单元测试只测试该单元引入的功能,而不测试单元的依赖关系


使用功能和测试功能是两件截然不同的事情。

我还认为直接在内部使用实例是可以的。 我的问题是模拟不属于我的代码的外部对象(通过静态库或DLL提供,有时是第三方)。 我倾向于重写具有相同类名的模拟DLL或库,然后进行不同的链接以进行测试。修改外部依赖项的头文件以添加“虚拟”对我来说似乎是不可接受的。
有谁有更好的解决方案吗?

我个人更喜欢工作单元测试和简单、干净、可维护的设计,而不是遵循单元测试纯粹主义者的一些理想设置。我喜欢这种反应——保持实际。