Use gMock for a class instantiated in smart pointers

44 Views Asked by At

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:

  1. 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;
};
  1. There's a class that can be "injected" with DrawI objects 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?

0

There are 0 best solutions below