Strange heap checker error in death test
-
03-12-2019 - |
Domanda
I have a problem with one of my googletest unittests that uses a mock object and a death test. This is a minimized code sample that illustrates the problem:
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace ::testing;
class MockA {
public:
MockA() {};
virtual ~MockA() {};
MOCK_METHOD1(bla,int(int));
};
class B {
public:
B(MockA * a)
: a_(a) {};
void kill() {
exit(1);
}
MockA * a_;
};
TEST(BDeathTest,BDies) {
MockA * a = new MockA();
ON_CALL(*a,bla(_)).WillByDefault(Return(1));
B * b = new B(a);
EXPECT_DEATH(b->kill(),"");
delete a;
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
The output:
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BDeathTest
[ RUN ] BDeathTest.BDies
gtest.cc:27: ERROR: this mock object (used in test BDeathTest.BDies) should be deleted but never is. Its address is @0x7fe453c00ec0.
ERROR: 1 leaked mock object found at program exit.
[ OK ] BDeathTest.BDies (2 ms)
[----------] 1 test from BDeathTest (2 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (2 ms total)
[ PASSED ] 1 test.
It seems like googlemock checks for left over mock objects on the heap right after the EXPECT_DEATH
assertion, but deleting a
before invoking the macro is obviously not a good solution, as a
might be used in the function that's invoked. I would actually expect the check to occur at the end of the test suite deconstruction. What am I missing?
Soluzione
Since a
will be leaked, you need to tell gmock about this:
TEST(BDeathTest,BDies) {
MockA * a = new MockA;
ON_CALL(*a,bla(_)).WillByDefault(Return(1));
B * b = new B(a);
Mock::AllowLeak(a); // <=== Self-explanatory addition
EXPECT_DEATH(b->kill(),"");
delete a;
delete b;
}
You can also use ::testing::FLAGS_gmock_catch_leaked_mocks = false;
to switch off all gmock leak detection, but this is probably a bad habit to get into. It may be appropriate in this case however if you have a large number of mock objects when you call exit()
. It's also worth switching it back on immediately after EXPECT_DEATH
in case the test goes on to do further work (although in your example above, it's pointless to switch it back on).
TEST(BDeathTest,BDies) {
MockA * a = new MockA;
ON_CALL(*a,bla(_)).WillByDefault(Return(1));
B * b = new B(a);
FLAGS_gmock_catch_leaked_mocks = false; // <=== Switch off mock leak checking
EXPECT_DEATH(b->kill(),"");
FLAGS_gmock_catch_leaked_mocks = true; // <=== Re-enable mock leak checking
// in case the test is refactored
delete a;
delete b;
}
Finally, a third way to handle this particular case is to delete a_;
in B::kill()
rather than allowing it to leak.
class B {
...
void kill() {
delete a_;
exit(1);
}
MockA * a_;
};
TEST(BDeathTest,BDies) {
MockA * a = new MockA;
ON_CALL(*a,bla(_)).WillByDefault(Return(1));
B * b = new B(a);
EXPECT_DEATH(b->kill(),"");
delete a;
delete b;
}
Since gtest spawns a new process to execute the death test, you're safe to delete a_
just before exit
ing while also deleting a
inside the test fixture.
However, to someone who doesn't know how gtest death tests work, this would look like the same variable getting deleted twice, and could cause confusion.