2012-04-23 7 views
21

Ich benutze GoogleMock/GoogleTest zum Testen, und ich sehe ein seltsames Verhalten, wenn ein Matcher einen shared_ptr zu einem Mock als Parameter hat und EXPECT auf demselben shared_ptr aufgerufen wird. Der säumige Stück Code:Warum leert GoogleMock mein 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(); 
} 

Wenn dieser Test durchgeführt wird, bekomme ich

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. 

Jede Idee, warum dies geschieht? Ich muss eher nicht Mock::AllowLeak verwenden.

Antwort

26

Dies ist ein Ergebnis des Haltens als shared_ptr, mit und die Reihenfolge, in der Sie Ihre Erwartungen erklärt haben.

Wenn Sie

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

erhöhen Sie die use_count von p. Damit die Lecksuche erfolgreich ist, muss bei (oder vor) dem Ende TEST zerstört werden.

Das Problem hier ist, dass intern, Gmock hält eine Aufzeichnung der erforderlichen mock Aufrufsequenz durch einen Zeiger auf die vorherige Erwartung halten. Also, wenn Sie EXPECT_CALL(*p, myMethod()); aufrufen, erhält es eine Kopie des Zeigers auf die vorherige Erwartung.

Dies hat dann die Wirkung, den Aufruf des Destruktors p zu blockieren, wenn TEST endet.

Um dies zu umgehen, ich denke, Ihre beste Wette

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

nur zu nennen ist, bevor Sie TEST verlassen. Dies löscht die Erwartungen an , einschließlich kritisch seine vorausgesetzte Erwartung, die wiederum ermöglicht, den Destruktor von p korrekt aufgerufen werden.

Alternativ, wenn die Reihenfolge der Mock-Aufrufe ist unwichtig, einfach Entfernen InSequence dummy; ermöglicht auch p Destruktor ausgeführt werden.


Nebenbei, Ihr Code hat ein paar Probleme;

  • Ihre Basis structs sollte gmock die Funktion zu ermöglichen, außer Kraft zu setzen es Fraser virtuellen Destruktoren
  • MyClass::myMethod sollten, um
  • p->myMethod(p); sollte p->myMethod();
+0

Es funktioniert, virtuell sein! Ich habe den Code auch nach Ihren Vorschlägen korrigiert. –

+0

@bruno nery: Welche Version von GoogleMock verwenden Sie? –

+0

Was würde passieren, wenn p vor c erstellt wird? Wäre nicht am Ende c zerstört, würden seine Erwartungen verifiziert und geklärt, was zur Verringerung des Referenzzählers von p führen würde. Danach wird p zerstört, verifiziert und vollständig zerstört, da der Zähler jetzt 0 ist. –