我使用 Google Test 进行了大量的单元测试。
目前使用 XCode,我注意到其他一些测试框架会在每个单元测试结束时检测内存泄漏,并且我认为有一种规定的方法可以使用 Google Test 执行相同的操作。我希望这不仅仅是 Boost Test 和其他一些功能的功能。
如果有人能指出我正确的方向,我将不胜感激。而是避免切换测试框架。
现在,我认为 valgrind 可能值得研究,我只是不确定如何参与每个测试。我的猜测是我无法直接从 xcode 执行此操作。
据我所知,Google Test 中并未明确支持内存泄漏的单元测试。不过,您有这个扩展可以为您填补该部分
我发现使用 gperf 的工具 - 堆检查器(也是由 Google 提供) 非常强大,同时也易于使用(至少在其非常基本的形式中)。
前言:为了简化(从我的角度来看)与安装、链接和包含简单程序所需的包有关的所有“后勤”,我正在使用
cmake
工具。
物流:我正在使用 Ubuntu 22.04 64 位以及
glibc 2.35
、gcc 11.04
和 cmake 3.22.1
。
要安装 cmake
,请运行:sudo apt-get install cmake
。
其余的可能存在于您的 Linux 发行版上。
安装
gperf
软件包以及 tcmalloc
:为了使用 gperf 软件包,应该像这样安装:sudo apt-get install google-perftools libgoogle-perftools-dev
。
安装软件包后,您将在以下位置找到其 .so
文件:/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4
。
让链接器知道库位置的一种方法是在 /lib/x86_64-linux-gnu
下创建指向它的符号链接。
另外,请确保在 /usr/include/gperftools/
下有 heap-checker.h
文件。
注意:tcmalloc
是 Google 实施的版本,用于替换(如果需要/期望)glibc
的 malloc
。可以在这里找到。
另请注意,如果您希望保持 glibc
的正常状态 malloc
,您可以这样做(您不必将应用程序本身的可执行文件链接到 tcmalloc
)。
源文件: 我为此示例编写的最少代码采用以下“结构”:
├──构建(文件夹)
├── CMakeLists.txt
└──unitTestsMain.cpp
unitTestsMain.cpp:下面是一个非常简单且纤薄的C++对象,在其实现中存在内存泄漏。此外,还有
createSingleMySampleObject
GTest 单元测试函数来说明 heap_checker
如何捕获内存泄漏。
#include <iostream>
#include <gtest/gtest.h>
#include <gperftools/heap-checker.h>
using namespace std;
class MySampleObject
{
public:
MySampleObject(int i, short s)
{
m_i = new int;
m_s = new short;
*m_i = i;
*m_s = s;
}
~MySampleObject()
{
delete m_i;
//delete m_s; --> this is the itentional memory leak!
}
int *m_i;
short *m_s;
};
TEST(sampleObjectTest, createSingleMySampleObject)
{
cout << "sampleObjectTest::createSingleMySampleObject - start" << endl;
HeapLeakChecker heap_checker("test_MySampleObject");
{
MySampleObject* pTestedObj = new MySampleObject(12, 17);
delete pTestedObj;
}
if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");
cout << "sampleObjectTest::createSingleMySampleObject - end" << endl;
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
cout << "main - START of unit tests" << endl;
int unitTestRetCode = RUN_ALL_TESTS();
cout << "main - END of unit tests" << endl;
return unitTestRetCode;
}
project(SampleUnitTestWithTcmallocAndGtest)
message(STATUS "unit tests CMakeLists.txt of ${CMAKE_PROJECT_NAME}")
cmake_minimum_required(VERSION 3.22.1)
set(CMAKE_CXX_STANDARD 20) # Add/customize global project settings:
# Locate GTest
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
# Link runTests with what we want to test and the GTest and pthread library
find_library(GTEST_LIBRARY gtest HINTS /usr/lib)
set(testsExeName "unitTests.out")
# unitTestsMain.cpp is the only source file used in this "mini project" (will be shown later)
add_executable(${testsExeName} unitTestsMain.cpp)
# Add the binary tree to the search path for include files
# so that we will find the heap-checker.h (for example)
target_include_directories(${testsExeName} PUBLIC /usr/include/gperftools)
# NOTES:
# tcmalloc - is linked in order to use tcmalloc in the unit tests instead of glibc malloc - only
# for the sake of using the heap checker feature of the tcmalloc library.
# pthread - is plain GTest requierment
target_link_libraries(${testsExeName} ${GTEST_LIBRARY} tcmalloc pthread)
构建: 为了构建这个简单的单元测试 main + 示例对象 + 其测试,请执行以下操作:
cd build && cmake ../ && make
运行测试(有泄漏): 在
build
文件夹中执行以下操作: env HEAPCHECK=local ./unitTests.out
您应该期望输出如下:
WARNING: Perftools heap leak checker is active -- Performance may suffer
main - START of unit tests
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from sampleObjectTest
[ RUN ] sampleObjectTest.createSingleMySampleObject
sampleObjectTest::createSingleMySampleObject - start
Have memory regions w/o callers: might report false leaks
Leak check test_MySampleObject detected leaks of 2 bytes in 1 objects
The 1 largest leaks:
Leak of 2 bytes in 1 objects allocated from:
@ 645d6b089313
@ 645d6b088d2c
@ 645d6b0c8ecd
@ 645d6b0c0b6d
@ 645d6b0938ac
@ 645d6b09433a
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof ./unitTests.out "/tmp/unitTests.out.9512.test_MySampleObject-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might h
unitTests.out: /home/guya/dev/tmpFolder/unitTestsMain.cpp:36: virtual void sampleObjectTest_createSingleMySampleObject_Test::TestBody(): Assertion `NULL == "heap memory leak"' failed.
Aborted (core dumped)
build
文件夹中运行 make
,然后像以前一样重新运行测试。
您期望得到以下输出:WARNING: Perftools heap leak checker is active -- Performance may suffer
main - START of unit tests
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from sampleObjectTest
[ RUN ] sampleObjectTest.createSingleMySampleObject
sampleObjectTest::createSingleMySampleObject - start
Have memory regions w/o callers: might report false leaks
No leaks found for check "test_MySampleObject" (but no 100% guarantee that there aren't any): found 38 reachable heap objects of 76941 bytes
sampleObjectTest::createSingleMySampleObject - end
[ OK ] sampleObjectTest.createSingleMySampleObject (4 ms)
[----------] 1 test from sampleObjectTest (4 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (4 ms total)
[ PASSED ] 1 test.
main - END of unit tests