Reputation: 4010
I am learning gmock and wondering how I can make my mock object do something when one of the mocked methods is called.
I need to mock some interfaces that make use of Qt and I am trying to get Qt and Gmock to work together.
For example, I mocked a network socket interface class, gave it to a network client class via constructor based DI, and I want to tell the mock socket to call one of its methods to signal the client when connection completes, in order to pretend a connection was made.
I see there is WillOnce
and it takes and "action" but the documentation I am reading doesn't really explain what kinds of things an "action" can be. All the examples simply return something or increment a global variable. Can you call methods belonging to the abstract class you are mocking?
If not, I see you can separately define a fake object and make it a member of the mock, and then delegate, but that seems like a hell of a lot of work to put into every test case that wants a different behavior.
Here is a bit of example code:
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
I want to prevent having to define an entirely new fake class and mock that delegates to it every single unit test case where actions would differ.
Please note, I am not looking for QSignalSpy or to verify signals and slots. I want to verify the functionality of my classes that react to them and have those classes use mock dependencies so I don't have to talk across the real network.
Upvotes: 0
Views: 790
Reputation: 7777
You should be able to use InvokeWithoutArgs
to achieve the result that you are looking for, assuming that you are using Qt 5 or greater. Your mock object should be defined as follows:
class MockMySocketInterface : public MySocketInterface
{
Q_OBJECT
public:
MockMySocketInterface() { }
virtual ~MockMySocketInterface() { }
MOCK_METHOD1(connect, void(std::string));
};
Your test would look something like the following:
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.
Upvotes: 1