簡體   English   中英

如何在 googlemock 中創建部分(混合)模擬?

[英]How can I create a partial (hybrid) mock in googlemock?

當您需要調用真實對象的功能時,Google 建議將調用委托給父對象,但這並不會真正創建部分(混合)模擬。 調用真實對象時,任何方法調用都是真實對象的方法調用,而不是模擬對象,您可能已經在其上設置了操作/期望。 如何創建僅將特定方法委托給真實對象的部分模擬,並將所有其他方法調用委托給模擬對象?

委托給真實對象示例

using ::testing::_;
using ::testing::AtLeast;
using ::testing::Invoke;

class MockFoo : public Foo {
 public:
  MockFoo() {
    // By default, all calls are delegated to the real object.
    ON_CALL(*this, DoThis())
        .WillByDefault(Invoke(&real_, &Foo::DoThis));
    ON_CALL(*this, DoThat(_))
        .WillByDefault(Invoke(&real_, &Foo::DoThat));
    ...
  }
  MOCK_METHOD0(DoThis, ...);
  MOCK_METHOD1(DoThat, ...);
  ...
 private:
  Foo real_;
};
...

  MockFoo mock;

  EXPECT_CALL(mock, DoThis())
      .Times(3);
  EXPECT_CALL(mock, DoThat("Hi"))
      .Times(AtLeast(1));
  ... use mock in test ...

模擬應該簡單地擴展真實對象,而不是創建真實對象的實例作為成員變量,然后默認情況下將所有調用委托給父對象。 您現在可以像往常一樣設置模擬; 設置新的ON_CALL將覆蓋對父級的默認調用。 我們讓多態為我們完成工作——所有調用,甚至來自父(真實)對象的調用,都會調用模擬對象,然后將ON_CALL語句設置為調用父對象或模擬行為。 我們已經成功地將真實對象行為與模擬行為混合在一起。 這與將調用委托給父類完全相同。

委托給父類示例

class Foo {
 public:
  virtual ~Foo();

  virtual void Pure(int n) = 0;
  virtual int Concrete(const char* str) { ... }
};

class MockFoo : public Foo {
 public:
  // Mocking a pure method.
  MOCK_METHOD1(Pure, void(int n));
  // Mocking a concrete method.  Foo::Concrete() is shadowed.
  MOCK_METHOD1(Concrete, int(const char* str));

  // Use this to call Concrete() defined in Foo.
  int FooConcrete(const char* str) { return Foo::Concrete(str); }
};

using ::testing::Invoke;
// Create mock instance foo.
...
// Delegate to parent.
ON_CALL(foo, Concrete(_))
    .WillByDefault(Invoke(&foo, &MockFoo::FooConcrete));

這種技術的唯一缺點是它需要大量樣板代碼並且對代碼更改很敏感。 我擴展了 googlemock 來簡化這個過程; 代碼可在此處獲得 它將生成默認情況下為所有方法調用父(真實)對象的部分模擬,並生成將參數傳遞給父構造函數的匹配構造函數。

官方的Google Mock 指南和最后一個提案確實有效,但是引入了很多樣板代碼。

所以這是我的建議:

Foo.h

class Foo {
 public:
  virtual ~Foo();

  virtual void Pure(int n) = 0;
  virtual int Concrete(const char* str) { ... }
};

MockFoo.h

class MockFoo: public Foo {
 using Real = Foo;
 public:
  MockFoo();
  virtual ~MockFoo();

  MOCK_METHOD1(Pure, void(int n));
  MOCK_METHOD1(Concrete, int(const char* str));
};

MockFoo.cpp

MockFoo::MockFoo() {
 using ::testing::Invoke;
 ON_CALL(*this, Pure()).WillByDefault(Invoke([this] {return Real::Pure();}));
 ON_CALL(*this, Concrete()).WillByDefault(Invoke([this] {return Real::Concrete();}));
};

MockFoo::~MockFoo() = default;

值得注意的是,擁有模擬的實現文件是一種很好的做法,對測試編譯時間有明顯的好處。 好,易於。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM