我的一个googletest单元测试使用模拟对象和死亡测试时出现问题。这是一个最小化的代码示例,用于说明问题:
#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();
}
输出:
[==========] 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.
似乎googlemock在EXPECT_DEATH
断言后立即检查堆上的左侧模拟对象,但在调用宏之前删除a
显然不是一个好的解决方案,因为a
可能在被调用的函数中使用。我实际上希望检查在测试套件解构结束时发生。我错过了什么?
答案 0 :(得分:2)
由于a
将被泄露,你需要告诉gmock:
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;
}
您也可以使用::testing::FLAGS_gmock_catch_leaked_mocks = false;
关闭所有gmock泄漏检测,但这可能是一个不好的习惯。但是,在这种情况下,如果在调用exit()
时有大量模拟对象,则可能是合适的。如果测试继续进行进一步的工作,在EXPECT_DEATH
之后立即重新开启它也是值得的(尽管在上面的例子中,重新开启它是没有意义的。)
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;
}
最后,处理这种特殊情况的第三种方法是delete a_;
中的B::kill()
而不是允许它泄漏。
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;
}
由于gtest会产生一个执行死亡测试的新流程,因此您可以在a_
之前删除exit
,同时删除测试夹具中的a
。
然而,对于不知道gtest死亡测试如何工作的人来说,这看起来像是被删除两次的同一个变量,并且可能引起混淆。