2012-04-23 104 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