2012-04-23 105 views
21

我使用GoogleMock/GoogleTest进行测试,并且当匹配器将shared_ptr作为参数作为模拟,并且在相同的shared_ptr上调用EXPECT时,我看到一些奇怪的行为。违规的一段代码:为什么GoogleMock泄漏我的shared_ptr?

#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

回答

26

这是持有p作为shared_ptr,使用InSequence和您声明您的期望的顺序的结果。

当你调用

EXPECT_CALL(*c, myMethod(Eq(p))); 

你增加的puse_count。为了使泄漏检测通过,p必须在TEST结束时(或之前)销毁。

这里的问题是,在内部,gmock通过持有一个指向前面期望的指针来维护所需的模拟调用序列的记录。所以当你打电话给EXPECT_CALL(*p, myMethod());时,它会得到一个指向以前期望的指针的副本。

然后,当TEST结束时,它会阻止对p的析构函数的调用。

为了解决这个问题,我认为最好的方法是调用

EXPECT_TRUE(Mock::VerifyAndClearExpectations(p.get())); 

退出TEST之前。这清除了对p的期望,包括严格的先决条件期望,这反过来允许正确调用p的析构函数。

或者,如果模拟调用的顺序不重要,只需删除InSequence dummy;也将允许p的析构函数执行。


另外,您的代码有几个问题;

  • 您的基本结构应该有虚析构函数
  • MyClass::myMethod应该是虚拟的,以允许gmock的功能来覆盖它
  • p->myMethod(p);应该p->myMethod();
+0

它的工作原理,弗雷泽!我也根据你的建议更正了代码。 – 2012-04-30 21:23:19

+0

@bruno nery:您使用的是哪个版本的GoogleMock? – 2012-05-07 10:39:50

+0

如果在c之前创建p,会发生什么?不会比在最后c被破坏,它的期望得到验证并被清除,这将导致p的参考计数器递减。在此之后,由于计数器现在为0,p将被销毁,验证并完全销毁。 – 2012-05-07 11:44:46