Reputation: 19156
I am just getting started with GoogleTest and GoogleMock. Reading the "for dummies" documentation the example tests a Painter
class which depends on a Turtle
:
Real object - Turtle.h
class Turtle {
public:
virtual ~Turtle() {}
virtual void PenDown() = 0;
};
Mock object - mock-turtle.h
class MockTurtle : public Turtle {
public:
MOCK_METHOD0(PenDown, void());
};
Code under test - Painter.h
class Painter {
public:
Painter(Turtle *turtle){};
};
Unit test - test_painter.cpp
This is intended to test whether the turtle.PenDown()
method is called from the Painter
constructor.
TEST(PainterTest, CanDrawSomething) {
MockTurtle turtle;
EXPECT_CALL(turtle, PenDown())
.Times(AtLeast(1));
Painter painter(&turtle);
}
This test correctly fails because PenDown()
is never called.
But if I change the test to use a dereferenced pointer to MockTurtle
it incorrectly passes.
TEST(PainterTest, CanDrawSomething) {
MockTurtle *turtle = new MockTurtle();
EXPECT_CALL(*turtle, PenDown())
.Times(AtLeast(1));
Painter painter(turtle);
}
Why does this test pass when using a dereferenced pointer? Nowhere in my code is PenDown()
called.
For more context, I would like to use a pointer to MockTurtle
so that I can initialise it in a test fixture so that other tests can use it.
Upvotes: 3
Views: 1558
Reputation: 19156
In addition to @StoryTeller's excellent answer, I thought it would be useful to add some extra background, so no-one else is caught out by this issue.
I am using CLion as my test runner and because of this bug the error which was occurring after the tests have been run was not being displayed. Running my test binary from the terminal revealed it:
./test_painter --gtest_filter=* --gtest_color=no
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from PainterTest
[ RUN ] PainterTest.CanDrawSomething
[ OK ] PainterTest.CanDrawSomething (0 ms)
[----------] 1 test from PainterTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
/Users/donturner/PCode/workspace-kinetis/blinky/tests/test_painter.cpp:13: ERROR: this mock object (used in test PainterTest.CanDrawSomething) should be deleted but never is. Its address is @0x7fc06f402720.
ERROR: 1 leaked mock object found at program exit.
So I was forgetting to delete my pointer. I added the following line to the end of my test:
delete turtle;
And hey presto the test correctly fails:
$ ./test_painter --gtest_filter=* --gtest_color=no
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from PainterTest
[ RUN ] PainterTest.CanDrawSomething
/Users/donturner/PCode/workspace-kinetis/blinky/tests/test_painter.cpp:13: Failure
Actual function call count doesn't match EXPECT_CALL(*turtle, PenDown())...
Expected: to be called at least once
Actual: never called - unsatisfied and active
[ FAILED ] PainterTest.CanDrawSomething (0 ms)
[----------] 1 test from PainterTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] PainterTest.CanDrawSomething
1 FAILED TEST
If anyone can tell me why forgetting to delete a pointer results in PenDown()
being called I would be most interested!
Upvotes: 3
Reputation: 170203
You don't delete your pointer.
And it's not that forgetting to delete it is going to result in PenDown()
being pushed. The member is never called. But it's the destructor of MockTurtle
that reports the results to the framework.
When you leak it, nothing is reported. The framework thinks you ran an empty test (which vacuously passes), because it doesn't get any feedback.
When turtle
is an object (not a pointer), that has automatic storage duration, its destructor is called automatically at scope exit. That's why the error is reported.
This is just GoogleMock utilizing RAII for the boilerplate.
Upvotes: 5