Pourquoi GoogleMock perd-il mon shared_ptr?

J’utilise GoogleMock / GoogleTest à des fins de test et je constate un comportement étrange lorsqu’un matcher a un paramètre shared_ptr à un mock et que EXPECT est appelé sur le même shared_ptr. Le code incriminé:

#include  #include  #include  #include  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 p) {} }; struct MyClassMock : public MyClass { MOCK_METHOD1(myMethod, void(shared_ptr)); }; TEST(LeakTest, GoogleMockLeaksMatchedPointer) { shared_ptr c = make_shared(); shared_ptr p = make_shared(); { InSequence dummy; EXPECT_CALL(*c, myMethod(Eq(p))); EXPECT_CALL(*p, myMethod()); } c->myMethod(p); p->myMethod(); } 

Lorsque ce test est exécuté, je reçois

 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. 

Une idée de pourquoi cela se produit? Je préfère ne pas avoir à utiliser Mock::AllowLeak .

Cela résulte du maintien de p tant que shared_ptr , à l’aide de InSequence et de l’ordre dans lequel vous avez déclaré vos attentes.

Quand vous appelez

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

vous augmentez le use_count d’ use_count de p . Pour que la détection de fuite réussisse, p doit être détruit au plus tard à la fin de TEST .

Le problème ici est qu’en interne, gmock conserve un enregistrement de la séquence d’appels simulés requirejse en maintenant un pointeur sur l’attente précédente. Ainsi, lorsque vous appelez EXPECT_CALL(*p, myMethod()); , il obtient une copie du pointeur vers l’attente précédente.

Cela a alors pour effet de bloquer l’appel du destructeur de p la fin de TEST .

Pour résoudre ce problème, je pense que votre meilleur pari est d’appeler

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

juste avant de quitter TEST . Cela efface les attentes sur p , y compris de manière critique ses attentes préalables, ce qui permet à son tour au destructeur de p d’être invoqué correctement.

Sinon, si l’ordre des appels simulés n’est pas important, supprimez simplement le InSequence dummy; permettra également au destructeur de p de s’exécuter.

En passant, votre code a quelques problèmes;

  • Vos structures de base doivent avoir des destructeurs virtuels
  • MyClass::myMethod doit être virtuel pour permettre à la fonction de gmock de la remplacer
  • p->myMethod(p); devrait être p->myMethod();