Can
we verify that a mock object is properly destroyed? Of course! There is
a couple of subtle differences between mocking regular functions and
mocking destructors. Let's suppose we have a
Grinder object that destroys any
Piece object passed to its
grind method:
void Grinder::grind(Piece * piece) { delete piece;}Furthermore,
Grinder can accumulate a list of Pieces (actually, let it be a list of
pointers to Pieces) for destruction that will take place when Grinder
itself is destroyed. To add a Piece to the list, we define:
int Grinder::enqueue_piece(Piece * piece) { list_of_pieces_.push_back(piece); return list_of_pieces_.size();}Now, to keep the promise of destroying the queued pieces, Grinder's destructor is defined as follows:
Grinder::~Grinder() { for(list<Piece*>::iterator it = list_of_pieces_.begin(); it != list_of_pieces_.end(); it++) { delete *it; }}But
how can we mock the destructor of Piece so that we can verify that
Grinder really destroys Pieces in both scenarios (on grind method call
and on Grinder destruction)? Well, we can't really mock Piece's
destructor itself, but we can use a workaround: it's enough to define
MockPiece destructor so that it calls another function, such as destroy,
that will be used as a signal for us that the destructor has been
called.
class Piece { public: virtual ~Piece() {}};class MockPiece : public Piece { public: MOCK_METHOD0(destroy, void()); virtual ~MockPiece() { destroy(); }};Now, a test like:
TEST(Grinder, CanGrindPiece) { MockPiece * piece = new MockPiece; Grinder grinder; EXPECT_CALL(*piece, destroy()); grinder.grind(piece);}Will pass correctly (we know that grind method deletes the object passed as a pointer argument). But what about this test:
TEST(Grinder, CanGrindWhenDies) { MockPiece * p1 = new MockPiece; MockPiece * p2 = new MockPiece; MockPiece * p3 = new MockPiece; list<Piece*> list_of_pieces; list_of_pieces.push_back(p1); list_of_pieces.push_back(p2); list_of_pieces.push_back(p3); Grinder grinder; EXPECT_CALL(*p1, destroy()); EXPECT_CALL(*p2, destroy()); EXPECT_CALL(*p3, destroy()); grinder.enqueue_piece(p1); grinder.enqueue_piece(p2); grinder.enqueue_piece(p3); //Grinder dies after this line}If
you try out test example above with the correct implementation of
Grinder's destructor, it will pass. But try to comment out the delete
statement in Grinder's destructor and see what happens. Google Mock
prints error messages like:
.//Grinder_test.cpp:34:
ERROR: this mock object (used in test Grinder.CanGrindWhenDies) should
be deleted but never is. Its address is @0x809d5e0.but it
still reports that the test itself passed! We would like to have Google
Mock report test failure in this case, wouldn't we? The trouble is that
Grinder dies when our test is already finished (when it goes out of
TEST scope - it is an automatic object). The workaround here is to add
another "helper" test that will verify our expectations
after
the proper test has been finished. Let's do the following modification:
move MockPieces p1, p2 and p3 from CanGrindWhenDies test to global
scope. Then, let's add a short helper test:
TEST {::testing::Mock::VerifyAndClearExpectations(p1);::testing::Mock::VerifyAndClearExpectations(p1);::testing::Mock::VerifyAndClearExpectations(p1);}That's
it: this implementation of expectations and verification will yield
correct results ("helper" test passing or failing) depending on whether
Grinder's destructor is implemented correctly.
Exercise: try to
move VerifyAndClearExpectations statements to CanGrindWhenDies test and
see what happens when you run the test with correct and incorrect
implementation of Grinder's destructor.