谷歌模拟 Linux 上的免费系统功能总是以内存泄漏结束

问题描述

我正在尝试模拟 Linux 标准库中的一个简单函数。 strerror() 从 errno 返回错误消息。这是我的带有模拟功能的库:

~$ cat mylib.c
#include <string.h>
#include <stdio.h>

int myStrerror()
{
    int error_number = 0;

    char* buffer = strerror(error_number);
    fprintf(stdout,"Returned string =  '%s'\n",buffer);
    return 0;
}

#if defined (EXECUTABLE)
int main(int argc,char **argv)
{
    return myStrerror();
}
#endif

~$ g++ -pedantic-errors -Wall -c mylib.c

这是我的谷歌测试:

~$ cat test_mylib.cpp
#include "gtest/gtest.h"
#include "gmock/gmock.h"

int myStrerror();

class strerrorMock {
public:
    MOCK_METHOD(char*,strerror,(int));
};

strerrorMock strerrorMockObj;

char *strerror(int error_number) {
    return strerrorMockObj.strerror(error_number);
}

TEST(MockTestSuite,strerror)
{
    using ::testing::Return;

    char response[] = "mocked strerror function";

    EXPECT_CALL(strerrorMockObj,strerror(0))
        .WillOnce(Return(response));
    EXPECT_EQ(myStrerror(),0);
    ::testing::Mock::VerifyAndClearExpectations(&strerrorMockObj);
}


int main(int argc,char **argv) {
  ::testing::InitGoogleTest(&argc,argv);
  return RUN_ALL_TESTS();
}

~$ g++ -pedantic-errors -Wall \
        -o test_mylib.a \
        -I"$BUILD_DIR"/googletest-src/googletest/include \
        -I"$BUILD_DIR"/googletest-src/googlemock/include \
        test_mylib.cpp \
        "$BUILD_DIR"/lib/libgtestd.a \
        "$BUILD_DIR"/lib/libgmockd.a \
        ./mylib.o \
        -lpthread

这是正常返回的:

~$ ./mylib.a
Returned string = 'Success'

并运行测试给出:

~$ ./test_mylib.a
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from MockTestSuite
[ RUN      ] MockTestSuite.strerror
Returned string = 'mocked strerror function'
[       OK ] MockTestSuite.strerror (0 ms)
[----------] 1 test from MockTestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

test_mylib.cpp:32: 错误:这个模拟对象(在测试 MockTestSuite.strerror 中使用)应该被删除,但永远不会被删除。它的地址是@0x56114aa239e0。
错误:在程序退出时发现 1 个泄漏的模拟对象。当对象被破坏时,验证对模拟对象的期望。泄漏一个模拟意味着它的期望没有得到验证,这通常是一个测试错误。如果你真的打算泄漏一个模拟,你可以使用 testing::Mock::AllowLeak(mock_object) 来抑制这个错误,或者你可以使用假或存根代替模拟。

我该怎么做才能避免内存泄漏?

解决方法

问题是我们使用了系统库中的免费全局函数 strerror()。它并没有像往常一样被 Googlemock 的界面嘲笑。所以我们不需要接口。我们必须用一个自由函数来覆盖模拟函数,该函数必须是全局的,才能与系统函数处于同一范围内,因为它将替换它。这就是我们所做的:

strerrorMock strerrorMockObj;

char* strerror(int error_number) {
    return strerrorMockObj.strerror(error_number);
}

这里模拟的实例 strerrorMockObj 也在全局范围内,可以在函数内调用。但显然 Googletest 无法删除错误消息中指出的全局模拟对象。我发现的一种解决方案是像往常一样在测试宏中实例化模拟对象并存储指向它的全局指针,以便函数可以对其进行寻址:

strerrorMock* ptrStrerrorMockObj;
char* strerror(int error_number) {
    return ptrStrerrorMockObj->strerror(error_number);
}

TEST(MockTestSuite,strerror)
{
    strerrorMock strerrorMockObj;
    ptrStrerrorMockObj = &strerrorMockObj;
...
}

然后没有抱怨内存泄漏的完整测试程序如下所示:

~$ cat test_strerror.cpp
#include "gtest/gtest.h"
#include "gmock/gmock.h"

int myStrerror();

class strerrorMock {
public:
    MOCK_METHOD(char*,strerror,(int));
};

strerrorMock* ptrStrerrorMockObj;
char* strerror(int error_number) {
    return ptrStrerrorMockObj->strerror(error_number);
}

TEST(MockTestSuite,strerror)
{
    using ::testing::Return;

    strerrorMock strerrorMockObj;
    ptrStrerrorMockObj = &strerrorMockObj;

    char mockedstr[] = "mocked strerror function";
    EXPECT_CALL(strerrorMockObj,strerror(0))
        .WillOnce(Return(mockedstr));
    EXPECT_EQ(myStrerror(),0);
}

int main(int argc,char **argv) {
  ::testing::InitGoogleTest(&argc,argv);
  return RUN_ALL_TESTS();
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...