34

我使用 GoogleMock/GoogleTest 进行测试,当匹配器将 shared_ptr 作为模拟参数并在同一个 shared_ptr 上调用 EXPECT 时,我看到了一些奇怪的行为。有问题的代码:

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

运行此测试时,我得到

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.

知道为什么会这样吗?我宁愿不用Mock::AllowLeak

4

1 回答 1

37

这是持有pa shared_ptr、 usingInSequence和您声明期望的顺序的结果。

你打电话时

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

你增加use_countp。为了使泄漏检测通过,p必须在结束时(或之前)销毁TEST

这里的问题是,在内部,gmock 通过持有指向先前期望的指针来维护所需的模拟调用序列的记录。因此,当您调用 时EXPECT_CALL(*p, myMethod());,它会获得指向先前期望的指针的副本。

然后,这会在结束时阻止对p' 的析构函数的调用TEST

为了解决这个问题,我认为你最好的选择是跟注

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

就在你退出之前TEST。这清除了对 的期望p,包括关键的先决条件期望,这反过来又允许p正确调用析构函数。

或者,如果模拟调用的顺序不重要,简单地删除InSequence dummy;也将允许p' 的析构函数执行。


顺便说一句,您的代码有几个问题;

  • 你的基础结构应该有虚拟析构函数
  • MyClass::myMethod应该是虚拟的,以允许 gmock 的功能覆盖它
  • p->myMethod(p);应该p->myMethod();
于 2012-04-23T22:29:18.703 回答