轻松编写保持状态的模拟

时间:2016-04-15 20:27:22

标签: c++ unit-testing mocking googletest googlemock

我正在测试一些大量使用回调的代码,它看起来像这样:

class Client {
 public:
  Client(Socket socket) {
    socket->onA([this] {
        // call private Client methods....
      });
    socket->onB([this] {
        // call private Client methods...
      });
    // repeated for onC, onD, and onE
  }

  void Start();
  void Stop();
 private:
  // and almost all of the state is private
};

几乎完全通过Socket提供的界面与外界进行通信,如下所示:

class Socket {
 public:
  void onA(std::function<void()> callBack) = 0;
  void onB(std::function<void()> callBack) = 0;
  void onC(std::function<void()> callBack) = 0;
  void onD(std::function<void()> callBack) = 0;
  void onE(std::function<void()> callBack) = 0;

  // various other public methods
};

重要的是,我既可以验证已调用onX函数,也可以访问传递给它们的参数(因为Client&#39; s状态变化响应来自Socket的通知,我需要模拟我的测试中的那些。

我可以写一个看起来像的模拟:

class MockSocket : public Socket {
 public:
  MOCK_METHOD1(onA, void(std::function<void()> callBack));
  MOCK_METHOD1(onB, void(std::function<void()> callBack));
  // etc
};

但是我需要能够写出对表单的期望:&#34;期望这个MockSocket对象调用一次onA方法,现在调用作为参数传递的函数到onA。现在检查是否使用此字符串调用了write Socket方法:....&#34;

在另一种情况下,当我只有这种功能时,我做了类似的事情:

class MockSocket : public Socket {
 public:
  // as before

  void setCallbackForA(std::function<void()> callBack) {
    callbackForA = callBack;
  }

  void callCallbackForA() {
    callbackForA();
  }

  // etc

 private:
  std::function<void()> callbackForA;
  std::function<void()> callbackForB;
  // etc
};

但是要完成这项工作将会是一个荒谬的样板(5个getter和5个setter +所有EXPECT_CALL s,这将从测试用例到testcase),而我怀疑必须有更好的方法来做到这一点(不使用C风格的宏)。有一些模板魔法可以帮助吗?有什么可以让它更容易处理?

1 个答案:

答案 0 :(得分:2)

我假设您正在测试Client类 - 所以您真正需要的是存储ClientSocket中注册的回调函数。通过SaveArg<N>操作执行此操作。见代码:

class ClientTest : public ::testing::Test
{
public:
    std::function<void()> onACallback;
    std::function<void()> onBCallback;
    //...
    MockSocket mockSocket;
    std::unique_ptr<Client> objectUnderTest;
    void SetUp() override
    {
       using ::testing::SaveArg;
       EXPECT_CALL(mockSocket, onA(_)).WillOnce(SaveArg<0>(&onACallback));
       EXPECT_CALL(mockSocket, onB(_)).WillOnce(SaveArg<0>(&onBCallback));
       //...
       objectUnderTest = std::make_unique<Client>(mockSocket);

    }
};

使用上面的Test类 - 您可以收集所有回调。您可以使用这些捕获的回调来触发Client类中的操作,如下面的测试用例:

TEST_F(ClientTest, shallDoThisAndThatOnA)
{
   // here you put some expectations
   //...
   onACallback(); // here you trigger your Client object under test
   // now you make some assertions (post actions)
   //...
}