谷歌模拟全局模拟对象内存泄漏

Google mock global mock object memory leak

本文关键字:模拟 泄漏 内存 全局 谷歌 对象      更新时间:2023-10-16

我使用的是VS2005,C++使用google mock进行单元测试
我在单元测试中有一个全局自由函数,我使用以下代码来模拟自由函数:

NiceMock <MockA> mockObj;  

struct IFoo {  
    virtual A* foo() = 0;  
    virtual ~IFoo() {}  
};  
struct FooMock : public IFoo {  
    FooMock() {}  
    virtual ~FooMock() {}  
    MOCK_METHOD0(foo, A*());  
};
FooMock fooMock;
// foo() implementation  
A* foo() {  
    return fooMock.foo();  
}  

SetUp()函数中,我在全局对象(如)上设置Experiences

EXPECT_CALL(fooMock,foo())  
    .Times(1)  
    .WillOnce(Return(&mockObj));  
TEST(..., instA) {
    // ...
}

TearDown()中,我删除了全局模拟对象fooMock

virtual TearDown(){  
    delete &fooMock;  
}  

当我运行代码时,我得到以下错误

错误:xyz.instA,内存泄漏

此外,
0个可用块中有0个字节
--1个正常块中的61个字节
在7个CRT块中有68个字节
0忽略块中有0个字节
0个客户端块中有0个字节
使用的最大数字:11025字节
分配总数:50602字节。

有人能告诉我这里发生了什么吗?如果我不删除fooMock,我会得到错误"fooMock应该被删除,但从来没有被删除",或者检测到堆损坏
从错误中,我可以看出我的堆在某个地方处理不当,但我找不到重点。我也试着一步一步地调试它。

一些帮助会非常好!:)

正如Ian所说:

Googlemock/googletest期望mock可以在测试的主体中定义,也可以在测试夹具类中定义。

它背后的想法在食谱中有解释:

当它被破坏时,你的友好模拟对象会自动验证对它的所有期望都得到了满足,如果没有,就会产生谷歌测试失败。这很方便,因为它让你少了一件需要担心的事情。也就是说,除非您不确定您的模拟对象是否会被销毁。

在您的案例中,fooMock是一个全局变量(正如您所说,它必须保持这种状态),因此在每次测试后,您只需要运行手动验证:

    using ::testing::Mock;
    TEST(..., instA) 
    {
       ASSERT_TRUE(
           Mock::VerifyAndClearExpectations(
            &fooMock));
    }

由于它是一个全局变量,您也可以执行以下操作:

Mock::AllowLeak(&fooMock);

Cookbook中的更多详细信息-强制验证和备忘单-验证和重置模拟:

问题似乎是您正在实例化FooMock的全局实例。Googlemock/googletest期望mock可以在测试的主体中定义,也可以在测试夹具类中定义。

在上面的例子中,您只需在测试中实例化fooMock:

TEST(..., instA) {
    FooMock fooMock;
    // ...
}

所以我偶然发现了这个问题,想不出办法。但作为一名软件工程师,我需要找到一个解决方案。我就是这么做的。

假设您想模拟一个队列。要模拟的一个函数是出列。我假设您希望将整数出列以保持简单,因为我想演示如何在没有内存泄漏的情况下制作全局mock。

class QueueInterface {
    public:
        virtual ~QueueInterface() {};
        virtual int dequeue() = 0;
};
class QueueMock : public QueueInterface {
    public:
        virtual ~QueueMock() {};
        MOCK_METHOD(int, dequeue, (), (override));
};
// Instead of a global object, have a global pointer
QueueMock *globalQueue;
class TestFixture : public ::testing::Test {
    protected:
        QueueMock mockedQueue;
        void SetUp() {
            globalQueue = &mockedQueue; // Point the global pointer to this queue
        }
        void TearDown() {
            globalQueue = NULL;
        }
}
// Now you can use this global queue pointer in free function or
// C style functions and override the existing implementations.
// This way you can mock a global object.
int dequeueFromQueue() {
   return globalQueue->dequeue();
}
TEST_F(TestFixture, DEQUEUE_TEST) {
    // Write your test here to use global queue pointer
    // Deref pointer to get mocked object
    EXPECT_CALL(*globalQueue, dequeue);
}

这样,每当执行新的测试时,就会分配成员变量mockedQueue,然后在测试结束时解除分配。globalQueue每次都会指向每个测试的成员实例。

希望这能有所帮助!:)

我遇到了同样的问题,下面是解决方案(不确定内部到底发生了什么,因为全局mock obj最终会被销毁)。

std::unique_ptr ptrMockObj(新FooMock());

在测试用例结束时,删除mock obj ptr

测试(…,instA){。。。ptrMock.Object.reset()}