Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++, Googlemock - testing local object

I started to use googletest and googlemock libraries and I have a problem which I cannot solve. I have a code something like this:

class Painter
{
  public:
  void DrawSomething();
};

void Painter::DrawSomething()
{
  Turtle turtle;
 turtle.doSomething();
}

main()
{
  Painter p;
  p.DrawSomething();
}

I have mocked the Turtle class but how can I test doSomething() method (for example with EXPECT_CALL) when the object of turtle is created locally? Is it possible without modifying Painter class?

Thank you for answers.

like image 788
mcjay Avatar asked Apr 27 '16 17:04

mcjay


People also ask

Is gMock included in Gtest?

gMock is bundled with googletest.

What is gMock and Gtest?

In real system, these counterparts belong to the system itself. In the unit tests they are replaced with mocks. Gtest is a framework for unit testing. Gmock is a framework imitating the rest of your system during unit tests.

What is WillOnce in Gtest?

WillOnce(Return(x))" manipulates the expected value that it is always true. class Turtle { ... virtual int DoSomeMathTurtle(int , int); //Adds two ints together and returns them ... };


1 Answers

I have mocked the Turtle class ...

How exactly did you mock it?

... but how can I test doSomething() method (for example with EXPECT_CALL) when the object of turtle is created locally? Is it possible without modifying Painter class?
(Emphasis mine)

The straightforward answer is: No.

You cannot magically inject a mock instead of a real instance used in another class without decoupling via an interface.


You should have something like the following code instead:

struct ITurtle {
    virtual void PenUp() = 0;
    virtual void PenDown() = 0;
    virtual void TurnLeft(double degrees) = 0;
    virtual void Move(double distance) = 0;
    // ...
    virtual ~ITurtle() {}
};

struct TurtleMock : ITurtle {
    // Mock method declarations
    MOCK_METHOD0(PenUp, void ());
    MOCK_METHOD0(PenDown, void ());
    MOCK_METHOD1(TurnLeft, void (double));
    MOCK_METHOD1(Move, void (double));
};

class Turtle : public ITurtle {
public:
    void PenUp();
    void PenDown();
    void TurnLeft(double degrees);
    void Move(double distance);
};

Provide the real implementation for the above declarations in a separate translation unit.


class Painter {
public:
    Painter(ITurtle& turtle) : turtle_(turtle) {}   
    void DrawSomething();
private:
    ITurtle& turtle_;
};

void Painter::DrawSomething() {
    turtle_.PenDown();
    turtle_.TurnLeft(30.0);
    turtle_.Move(10.0);
    turtle_.TurnLeft(30.0);
    turtle_.Move(10.0);
    // ...
}

You can alternatively pass the ITurtle interface to the DrawSomething() function:

class Painter {
public:
    void DrawSomething(ITurtle& turtle);
};

void Painter::DrawSomething(ITurtle& turtle) {
    turtle.PenDown();
    turtle.TurnLeft(30.0);
    turtle.Move(10.0);
    turtle.TurnLeft(30.0);
    turtle.Move(10.0);
    // ...
}

int main() {
     NiceMock<TurtleMock> turtle;
     Painter p(turtle);
     // Painter p; <<< for the alternative solution

     EXPECT_CALL(turtle,PenDown())
         .Times(1);
     EXPECT_CALL(turtle,TurnLeft(_))
         .Times(2);
     EXPECT_CALL(turtle,Move(_))
         .Times(2);

     p.DrawSomething();
     //  p.DrawSomething(turtle); <<< for the alternative solution

}
like image 150
πάντα ῥεῖ Avatar answered Sep 22 '22 04:09

πάντα ῥεῖ