【问题标题】:Mock Multiple derived Derived class in cpp - google mock在 C++ 中模拟多个派生派生类 - google mock
【发布时间】:2021-06-04 11:53:40
【问题描述】:

我有一个继承自基本类的多个派生类,如下所示,我想模拟所有派生类。

我需要创建一个 MockBase 类还是需要在每个派生类模拟对象中重复基类方法?

注意:我想测试 Dervied1User 和 Dervied2User,因此想创建 MockDervied1 和 MockDerived2。 Dervied1User 调用了 Dervied1 和基类中的方法。

class base {
  base() { .. }
  virtual ~base(..) { ... }
  virtual bool method0(..) { ... }
  virtual bool method1(..) { ... }
  virtual void method2(..) { ... }
};

class Derived1 : public base {
  Derived1() { ... }
  virtual int method3(..) { ... }
  virtual int method4(..) { ... }
};

class Derived2 : public base() {
  Derived2() { ... }
  virtual int method5(..) { ... }
  virtual int method6(..) { ... }
};

class Derived3 : public base() {
  Derived2() { ... }
  virtual int method7(..) { ... }
  virtual int method8(..) { ... }
};

class Dervied1User {
 public:
  Dervied1User(std::unique_ptr<Derived1> d1_) : d1(std::move(d1_)) {}
    int method9(..) {...}
 private:
  std::unique_ptr<Derived1> d1;
};

class Dervied2User {
    ....
}

派生类的模拟看起来像这样吗? ?在所有 Derived 类 mocks 中重复 method0、method1、method2。

class MockDerived1 : pubic Derived1 {
  MOCK_METHOD(method0, ....)
  MOCK_METHOD(method1, ....)
  MOCK_METHOD(method2, ....)
  MOCK_METHOD(method3, ....)
  MOCK_METHOD(method4, ....)
}

class MockDerived2 : pubic Derived2 {
  MOCK_METHOD(method0, ....)
  MOCK_METHOD(method1, ....)
  MOCK_METHOD(method2, ....)
  MOCK_METHOD(method5, ....)
  MOCK_METHOD(method6, ....)
}

【问题讨论】:

  • 您可能已经知道这一点,但是为了其他人在这里的利益:首先使用非纯虚函数模拟类很容易出错,因为忘记模拟方法不会被捕获由编译器。通常,如果要模拟这样的类,您确实需要添加一个抽象接口根类,作为模拟目标以及在应用程序代码中传递的类型。总的来说,它也是更好的设计。
  • @Frank,我是谷歌测试的新手,不知道有纯虚函数的事实。谢谢你让我知道。我一定会考虑在不久的将来重构我的代码。

标签: c++ unit-testing googletest gmock


【解决方案1】:

选项 1:什么都不做

如果您在测试Derived1 期间不需要拦截对base 的调用,那么您无需执行任何操作。所讨论的方法都不是纯虚拟的,因此不模拟它们只会回退到基本实现。显然,这是否可能是高度上下文相关的。

class MockDerived1 : public Derived1 {
  MOCK_METHOD(method3, ....)
  MOCK_METHOD(method4, ....)
};

class MockDerived2 : public Derived2 {
  MOCK_METHOD(method5, ....)
  MOCK_METHOD(method6, ....)
};

注意选项 1 完全可用的事实是代码异味。当您想要模拟一个方法时,您可能会意外地这样做,而编译器会让您这样做。如果创建一个base 继承自的baseInterface 抽象基类是可能的,我会认真推荐它。

选项 2:在每个派生的模拟中重复基本模拟。

派生类的模拟看起来像这样吗? ?在所有 Derived 类 mocks 中重复 method0、method1、method2。

class MockDerived1 : public Derived1 {
  MOCK_METHOD(method0, ....)
  MOCK_METHOD(method1, ....)
  MOCK_METHOD(method2, ....)
  MOCK_METHOD(method3, ....)
  MOCK_METHOD(method4, ....)
};

class MockDerived2 : public Derived2 {
  MOCK_METHOD(method0, ....)
  MOCK_METHOD(method1, ....)
  MOCK_METHOD(method2, ....)
  MOCK_METHOD(method5, ....)
  MOCK_METHOD(method6, ....)
};

是的,这很好用!虽然它可能很烦人并且可能容易出错。如果您更改了base,则需要更新每个派生的模拟类,这在某些代码库中可能是一项繁重的工作。

注意选项 1 和 2 并不相互排斥,您可以选择需要模拟的方法,只要在测试期间执行 base 中的实现即可。

选项 3:使用宏

减少重复可以做的一个相当简单的事情是创建一个宏,将base 的模拟添加到任何给定的子类。一个明显的优势是,如果base 发生更改,您只需更改宏,所有模拟将立即更新。 Google mock 已经以宏观为中心,所以这是它们并非完全不合适的情况之一:

#define MOCK_BASE_MEMBERS() \
    MOCK_METHOD(method0, ....) \
    MOCK_METHOD(method1, ....) \
    MOCK_METHOD(method2, ....) \
// end of macro

class MockDerived1 : public Derived1 {
  MOCK_BASE_MEMBERS()
  MOCK_METHOD(method3, ....)
  MOCK_METHOD(method4, ....)
};

class MockDerived2 : public Derived2 {
  MOCK_BASE_MEMBERS()
  MOCK_METHOD(method5, ....)
  MOCK_METHOD(method6, ....)
};

#undef MOCK_BASE_MEMBERS

选项 4:MockBase

既然你在问题中提到它,让我们讨论一下MockBase 的含义。

有几种不同的方法可以实现这一点,但只有一种是远程可行的。

由于您希望您的类层次结构看起来像 base -&gt; Derived1 -&gt; MockBase -&gt; MockDerived1, 这意味着MockBase 需要为每个 Dervied 类从不同的基类继承。这是模板的工作:

template<typename T>
class MockBase : public T {
  MOCK_METHOD(method0, ....)
  MOCK_METHOD(method1, ....)
  MOCK_METHOD(method2, ....)
};

class MockDerived1 : public MockBase<Derived1> {
  MOCK_METHOD(method3, ....)
  MOCK_METHOD(method4, ....)
};

如果您对宏完全过敏,您可能想要这样做,但我个人认为这比必要的更复杂。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    相关资源
    最近更新 更多