2012-04-23 13 views
21

Io uso GoogleMock/GoogleTest per testare e vedo strani comportamenti quando un matcher ha una shared_ptr su un mock come parametro e EXPECT viene chiamato sullo stesso shared_ptr. Il pezzo incriminato di codice:Perché GoogleMock perde il mio 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(); 
} 

Quando viene eseguito questo test, ho

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. 

Qualsiasi idea del perché questo accade? Piuttosto non devo usare Mock::AllowLeak.

risposta

26

Questo è il risultato del mantenimento di p come shared_ptr, utilizzando InSequence e l'ordine in cui si sono dichiarate le proprie aspettative.

Quando si chiama

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

si aumenta la use_count di p. Per consentire il rilevamento delle perdite, p deve essere distrutto a (o prima) alla fine di TEST.

Il problema qui è che internamente, gmock mantiene un record della sequenza di chiamate simulate richiesta tenendo un puntatore all'aspettativa precedente. Quindi quando chiami EXPECT_CALL(*p, myMethod());, ottiene una copia del puntatore rispetto all'aspettativa precedente.

Questo ha quindi l'effetto di bloccare la chiamata al distruttore p quando termina TEST.

Al fine di ovviare a questo, penso che la cosa migliore è chiamare

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

poco prima di uscire TEST. Ciò cancella le aspettative su p, includendo criticamente le sue aspettative sui prerequisiti, che a sua volta consente al distruttore di p di essere invocato correttamente.

In alternativa, se l'ordine delle chiamate simulate non è importante, è sufficiente rimuovere InSequence dummy; per consentire l'esecuzione del distruttore p.


Per inciso, il codice presenta un paio di problemi;

  • vostri le strutture di base devono avere distruttori virtuali
  • MyClass::myMethod dovrebbe essere virtuale al fine di consentire la funzione di gmock di ignorare che
  • p->myMethod(p); dovrebbe essere p->myMethod();
+0

Funziona, Fraser! Ho corretto il codice secondo i tuoi suggerimenti. –

+0

@bruno nery: quale versione di GoogleMock stai utilizzando? –

+0

Cosa succederebbe se p venisse creato prima di c? Non sarebbe distrutto alla fine c, le sue aspettative verificate e cancellate che porteranno a diminuire il contatore di riferimento di p. Dopo questo p sarà distrutto, verificato e completamente distrutto dal momento che il contatore è ora 0. –

Problemi correlati