c++ Google模拟全局模拟对象内存泄漏

vnzz0bqm  于 2023-02-10  发布在  Go
关注(0)|答案(4)|浏览(180)

我正在使用VS2005和C++进行单元测试,使用谷歌模拟。
我在单元测试中有一个全局自由函数,我使用了下面的代码来模拟自由函数:

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()函数中,我在全局对象上设置了Expectations,如

EXPECT_CALL(fooMock,foo())  
    .Times(1)  
    .WillOnce(Return(&mockObj));  

TEST(..., instA) {

    // ...
}

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

virtual TearDown(){  
    delete &fooMock;  
}

当我运行代码时,我得到以下错误
错误:xyz中的内存泄漏。instA,
而且,
0个可用块中的0个字节。
正常块中的61个字节。
7个CRT块中的68个字节。
0忽略块中的0字节。
0个客户端块中的0个字节。
使用的最大数量:11025字节
拨款总额:50602字节。
有人能告诉我这里发生了什么吗?如果我不删除fooMock,我会得到错误"fooMock应该被删除,但从来没有",或堆损坏检测。
从错误中,我可以看出堆的某个地方被错误处理了,但是我找不到错误的地方,我也试着一步一步地调试它。
一些帮助真的会很棒!:)

8cdiaqws

8cdiaqws1#

Ian所述:
Googlemock/Googletest希望模拟可以在测试主体中定义,或者在测试固定类中定义。
背后的想法解释在食谱:
当它被销毁时,友好的模拟对象会自动验证它是否满足所有期望,如果不满足,则会生成Google Test失败。这很方便,因为它让你少了一件要担心的事情。也就是说,除非你不确定你的模拟对象是否会被销毁。
在您的例子中,fooMock是一个全局变量(正如您所说的,它必须保持这种状态),所以在每次测试之后,您只需要运行手动验证:

using ::testing::Mock;

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

因为它是一个全局变量,你也可以这样做:

Mock::AllowLeak(&fooMock);

更多详细信息请参见操作手册-强制验证和备忘单-验证和重置模拟:

e0uiprwp

e0uiprwp2#

看起来问题是你示例化了一个全局的FooMock示例,Googlemock/googletest期望mock要么在测试的主体中定义,要么在测试fixture类中定义。
在上面的例子中,你只需在测试中示例化fooMock:

TEST(..., instA) {

    FooMock fooMock;
    // ...
}
brqmpdu1

brqmpdu13#

我遇到了同样的问题,这里是解决方案(不确定里面到底发生了什么,因为全局模拟对象最终将被销毁)。
std::unique_ptr ptrMockObj(新的食物模拟());
在测试用例结束时,删除模拟对象指针
测试(...,instA){...点模拟对象复位()}

lb3vh1jj

lb3vh1jj4#

我偶然发现了这个问题,但找不到解决的方法。但是作为一名软件工程师,我需要找到一个解决方案。所以我就这么做了。
假设你想模拟一个队列,你想模拟的一个函数是出队,我假设你想让整数出队,以保持事情简单,因为我想演示如何在没有内存泄漏的情况下进行全局模拟。

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每次都会指向每个测试的成员示例。
希望这有帮助!:)

相关问题