我使用GoogleMock / GoogleTest进行测试,当匹配器将模拟器的shared_ptr作为参数时,我会看到一些奇怪的行为,并且在同一个shared_ptr上调用EXPECT。令人讨厌的代码:
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
using namespace boost;
using namespace testing;
struct MyParameter
{
virtual ~MyParameter() {}
virtual void myMethod() = 0;
};
struct MyParameterMock : public MyParameter
{
MOCK_METHOD0(myMethod, void());
};
struct MyClass
{
virtual ~MyClass() {}
virtual void myMethod(shared_ptr<MyParameter> p) {}
};
struct MyClassMock : public MyClass
{
MOCK_METHOD1(myMethod, void(shared_ptr<MyParameter>));
};
TEST(LeakTest, GoogleMockLeaksMatchedPointer)
{
shared_ptr<MyClassMock> c = make_shared<MyClassMock>();
shared_ptr<MyParameterMock> p = make_shared<MyParameterMock>();
{
InSequence dummy;
EXPECT_CALL(*c, myMethod(Eq(p)));
EXPECT_CALL(*p, myMethod());
}
c->myMethod(p);
p->myMethod();
}
运行此测试时,我
leak_ptr_mock.cpp:37: ERROR: this mock object (used in test LeakTest.GoogleMockLeaksMatchedPointer) should be deleted but never is. Its address is @0x9309544.
ERROR: 1 leaked mock object found at program exit.
知道为什么会这样吗?我宁愿不必使用Mock::AllowLeak
。
答案 0 :(得分:30)
这是将p
作为shared_ptr
,使用InSequence
以及您宣布期望的顺序的结果。
致电时
EXPECT_CALL(*c, myMethod(Eq(p)));
您增加use_count
的{{1}}。为了通过泄漏检测,必须在p
结束时(或之前)销毁p
。
这里的问题是在内部,gmock通过保持指向前一个期望的指针来维护所需模拟调用序列的记录。因此,当您调用TEST
时,它会获得指向先前期望的指针的副本。
这样就可以在EXPECT_CALL(*p, myMethod());
结束时阻止对p
的析构函数的调用。
为了解决这个问题,我认为最好的办法是致电
TEST
退出 EXPECT_TRUE(Mock::VerifyAndClearExpectations(p.get()));
之前。这清除了对TEST
的期望,包括其前提条件的期望,这反过来允许正确调用p
的析构函数。
或者,如果模拟调用的顺序不重要,只需删除p
也将允许InSequence dummy;
的析构函数执行。
顺便说一下,你的代码有几个问题;
p
应该是虚拟的,以便允许gmock的功能覆盖它MyClass::myMethod
应为p->myMethod(p);