C++ Gmock - WillOnce - 除了 return 一个值,你还能做任何事情吗?

C++ Gmock - WillOnce - Can you do anything aside from return a value?

我正在学习 gmock 并且想知道如何让我的模拟对象在调用其中一个模拟方法时做某事。

我需要模拟一些使用 Qt 的接口,我正在尝试让 Qt 和 Gmock 一起工作。

例如,我模拟了一个网络套接字接口 class,通过基于 DI 的构造函数将其提供给网络客户端 class,我想告诉模拟套接字调用其方法之一在连接完成时向客户端发出信号,以假装已建立连接。

我看到有 WillOnce 它需要和“行动”,但我正在阅读的文档并没有真正解释“行动”可以是什么类型的事情。所有示例都只是 return 一些东西或增加一个全局变量。您可以调用属于您正在模拟的抽象 class 的方法吗?

如果没有,我看到你可以单独定义一个假对象并使它成为 mock 的成员,然后委托,但这似乎需要大量工作才能放入每个需要不同的行为。

这里有一些示例代码:

class MySocketInterface : QObject
{
    Q_OBJECT
    public:
   
       virtual void connect(std::string url) = 0;
       
    signal:    // Specific to Qt, but this is what I need to call
       // Notifies subscribers
       void connected();
 }

 class MyThingToTest
 {
 public:
     MyThingToTest(std::unique_ptr<MySocketInterface> && socket);
     void connect(std::string url);
     State getState() const;
 private:
     std::unique_ptr<MySocketInterface> m_socket;
     // Changes state to connected
     void onConnected();
 }

 Test1:
 ) Make a mock socket
 ) Give it to MyThingToTest
 ) Call MyThingToTest::connect
 ) mock socket needs to send notification faking connecting by calling `emit connected`
 ) Check if MyThingToTest is in connected state

 Test2:
 ) Make a mock socket
 ) Give it to MyThingToTest
 ) Call MyThingToTest::connect
 ) mock socket needs to not send notification, and 30 seconds needs to elapse.
 ) Check if MyThingToTest is in an error state

我想避免必须定义一个全新的假 class 并模拟委托给它的每个单元测试用例,其中操作会有所不同。

请注意,我不是在寻找 QSignalSpy 或验证信号和插槽。我想验证我的 classes 对它们做出反应的功能,并让那些 classes 使用模拟依赖项,这样我就不必通过真实网络进行交谈。

假设您使用的是 Qt 5 或更高版本,您应该能够使用 InvokeWithoutArgs 获得您正在寻找的结果。您的模拟对象应定义如下:

class MockMySocketInterface : public MySocketInterface
{
    Q_OBJECT
public:
    MockMySocketInterface() { }
    virtual ~MockMySocketInterface() { }

    MOCK_METHOD1(connect, void(std::string));
};

您的测试将如下所示:

auto socket = std::make_unique<MockMySocketInterface>(); // Could also use NiceMock here.

// This could alternately be an EXPECT_CALL, but you would need to use WillOnce
// or WillRepeatedly instead of WillByDefault.
ON_CALL(*socket, connect(_))
    .WillByDefault(InvokeWithoutArgs(socket.get(), &MockMySocketInterface::connected));
MyThingToTest thing(socket);

// etc.