Вопрос по c++, boost, googletest, googlemock, shared-ptr – Почему GoogleMock пропускает мой shared_ptr?

27

Я использую GoogleMock / GoogleTest для тестирования, и я вижу странное поведение, когда средство сопоставления имеет параметр shared_ptr для макета в качестве параметра и EXPECT вызывается для того же shared_ptr. Оскорбительный кусок кода:

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

Когда этот тест запущен, я получаю

<code>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.
</code>

Есть идеи, почему это происходит? Я скорее не должен использоватьMock::AllowLeak.

Ваш Ответ

1   ответ
30

p какshared_ptr, с помощьюInSequence и порядок, в котором вы заявили о своих ожиданиях.

Когда вы звоните

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

Вы увеличиваетеuse_count изp, Для того, чтобы обнаружение утечки прошло,p должен быть уничтожен в (или до) концеTEST.

Проблема здесь в том, что внутренне gmock поддерживает запись необходимой последовательности ложных вызовов, удерживая указатель на предыдущее ожидание. Поэтому, когда вы звонитеEXPECT_CALL(*p, myMethod());, он получает копию указателя на предыдущее ожидание.

Это затем имеет эффект блокировки вызоваpдеструктор, когдаTEST заканчивается.

Чтобы обойти это, я думаю, вам лучше всего позвонить

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

как раз перед выходомTEST, Это очищает ожиданияpвключая критическое ожидание, что, в свою очередь, позволяет деструкторуp быть вызванным правильно.

В качестве альтернативы, если порядок ложных вызовов не важен, просто удалитеInSequence dummy; также позволитpдеструктор для выполнения.


Кроме того, у вашего кода есть пара проблем;

Your base structs should have virtual destructors MyClass::myMethod should be virtual in order to allow gmock's function to override it p->myMethod(p); should be p->myMethod();
@bruno nery: Какую версию GoogleMock вы используете?
Что произойдет, если p создан до c? Если в конце не будет уничтожено, его ожидания проверены и очищены, что приведет к уменьшению счетчика ссылок p. После этого p будет уничтожено, проверено и полностью уничтожено, поскольку счетчик теперь равен 0.
@ Martin Нет, порядок построения не влияет на порядок проверок, посколькуInSequence dummy; используется. Менять местами порядокEXPECT_CALLs позволил бы успешно завершить тест без утечек, но если порядок ожиданий не имеет значения, вы также не используетеInSequence совсем. Кстати, я использую gmock 1.6.0.
Это работает, Фрейзер! Я исправил код в соответствии с вашими предложениями тоже. bruno nery
Что будет еслиp такое структура?

Похожие вопросы