I'm reading the gMock guide and find most of the examples showing how to use mock tests on "value" objects which seems odd since a big part of mocking is taking advantage of polymorphism (so use pointers or references):
// Canonical example.
TEST(PainterTest, CanDrawSomething) {
MockTurtle turtle;
EXPECT_CALL(turtle, PenDown()).Times(AtLeast(1));
Painter painter(&turtle);
EXPECT_TRUE(painter.DrawCircle(0, 0, 10));
}
My use case starts from a design (already in place), where mocking should be natural to use. To summarize the design, I'll use an example similar to the above:
- There's an interface for drawing
struct DrawI {
virtual void point(int x1, int y1);
virtual void line(int x1, int y1, int x2, int y2) = 0;
};
- There's a class that can be "injected" with
DrawIobjects that know how to draw:
struct DeviceIO {
DeviceIO(std::shared_ptr<DrawI> drawer, OtherProperties props);
draw(Type t, Info i) {
// Uses the implementation of DrawI supplied by the user.
}
// More methods here like log, persist, commit to Db
// All of them depend on action objects that follow
// an interface and users can supply their own or use the default behavior.
}
I hope this simplification doesn't miss the point which is: the behavior of DeviceIO can be tweaked by providing tailored implementations of objects like DrawI.
The test suite uses mocking by creating dedicated classes for the available interfaces:
struct NoOpDraw : DrawI {
virtual void point(int x, int y) override { /*implementation*/ }
virtual void line(int x1, int y1, int x2, int y2) override { /*implementation*/ }
}
TEST(Device, Operations) {
std::shared_ptr<DrawI> painter = std::make_shared<NoOpDraw>();
DeviceIo io(painter, /* other properties */)
// Normal Google test assertions (no gmock use)
}
The thing I find annoying is that gMock is not used/leveraged. But when trying to use it I find it impossible: I can define NoOpDraw as per the gMock requirements but when trying to use it I can only pass values to the EXPECT_CALL macros:
std::shared_ptr<DrawI> painter = std::make_shared<NoOpDraw>();
DeviceIo io(painter, /* other properties */);
EXPECT_CALL(*painter, point).Times(1);
// Using the io object in assertions will end up calling the mock
// methods, but not for the object I passed to the `DeviceIO` constructor.
EXPECT_NO_THROW(io.draw(Point, /* info */);
Is there a solution? How can I use gMock to test objects conforming to an interface when the objects themselves are used polymorphically as part of a different class?