c++ boost shared-ptr googletest googlemock

c++ - ¿Por qué GoogleMock pierde mi shared_ptr?



boost shared-ptr (1)

Uso GoogleMock / GoogleTest para probar, y estoy viendo un comportamiento extraño cuando un matcher tiene un shared_ptr a un simulacro como parámetro, y se llama a EXPECT en el mismo shared_ptr. La pieza ofensiva de código:

#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(); }

Cuando se ejecuta esta prueba, obtengo

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.

¿Alguna idea de por qué sucede esto? Preferiría no tener que usar Mock::AllowLeak .


Esto es el resultado de mantener p como shared_ptr , utilizando InSequence y el orden en el que ha declarado sus expectativas.

Cuando usted llama

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

aumentas el use_count de p . Para que la detección de fugas pase, p debe destruirse en (o antes) al final de TEST .

El problema aquí es que internamente, gmock mantiene un registro de la secuencia requerida de simulacros de llamada manteniendo un puntero a la expectativa anterior. Entonces cuando llamas a EXPECT_CALL(*p, myMethod()); , obtiene una copia del puntero a la expectativa anterior.

Esto tiene el efecto de bloquear la llamada al destructor de p cuando finaliza TEST .

Para evitar esto, creo que tu mejor opción es llamar

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

justo antes de salir de TEST . Esto borra las expectativas en p , incluida críticamente su expectativa de requisito previo, que a su vez permite que el destructor de p se invoque correctamente.

Alternativamente, si el orden de las llamadas simuladas no es importante, simplemente eliminando el InSequence dummy; también permitirá la ejecución del destructor de p .


Como un aparte, su código tiene un par de problemas;

  • Tus estructuras base deberían tener destructores virtuales
  • MyClass::myMethod debe ser virtual para permitir que la función de gmock lo anule
  • p->myMethod(p); debería ser p->myMethod();