开始使用 CppUTest
鸟
2017年5月14日
电子邮件
1 min read

关键要点
CppUTest 是一个轻量级、积极维护的 xUnit 风格测试框架,适用于 C/C++,具有无缝工作的 C 集成层,即使在以 C 为主的代码库中也是如此。
您可以通过包管理器(Linux 发行版,Homebrew)安装它,或克隆 GitHub 代码库。
最低配置包括:
一个生产
src/目录,一个
t/测试目录,一个测试运行器(
CommandLineTestRunner),以及使用
TEST_GROUP和TEST()模块的测试。
CppUTest 提供了一个 MakefileWorker.mk 辅助工具,简化了测试构建、库链接和标志处理。
内存泄漏检测默认情况下通过 malloc/free 重写启用,捕获测试源代码中的泄漏。
通过启用
CPPUTEST_USE_GCOV=Y,代码覆盖率 可以轻松集成,生成完整的覆盖率报告和 HTML 摘要。该框架包括高级功能:模拟、插件、辅助脚本以及直接的 C 互操作性——对复杂的企业代码库非常有用。
Q&A 精华
CppUTest是什么,为什么使用它?
它是一个功能强大的 xUnit 风格测试框架,适用于 C/C++,具有简洁的 API、内置断言宏、泄漏检测和积极开发——非常适合遗留或现代系统。
如何使用 CppUTest 构建一个基本项目?
src/ code/ code.cpp code.h main.cpp t/ main.cpp (test runner) test.cpp (test suite)
你如何运行所有测试?
测试运行器使用:
return CommandLineTestRunner::RunAllTests(ac, av);
如何在不手动配置编译器选项的情况下构建测试?
使用 CppUTest 的
MakefileWorker.mk,它可以自动处理标志、链接和测试执行。CppUTest能自动检测内存泄漏吗?
是的。它在测试版本中覆盖了 malloc/free,报告:
哪个测试泄漏了,
它发生在哪里,
泄漏大小和内存内容。
示例故障输出:
Memory leak(s) found. Allocated at: code.c line 6 Leak size: 1
如何生成代码覆盖率?
启用:
CPPUTEST_USE_GCOV=Y确保
filterGcov.sh位于$(CPPUTEST_HOME)/scripts/。运行:make
gcov这将生成
.gcov、总结文本和HTML覆盖率报告。
除了基本测试之外,CppUTest还能做些什么?
模拟框架
插件系统
助手自动化脚本
原生C集成
广泛的断言宏
Who is CppUTest best suited for?
与嵌入式系统、C 平台、C++ 服务或任何需要持续验证可靠性和内存安全性的环境合作的团队。
在 SparkPost,我们投入了大量时间和精力来测试我们的代码。我们的平台是用 C 语言编写的,最近我研究了如何与一个名为 “CppUTest” 的单元测试框架集成,该框架为 C/C++ 提供 xUnit 风格的测试。这个框架功能强大、功能丰富,并且在积极开发中,因此是一个很好的选择。它还提供了一个 C 集成层,使得即使框架的大部分是 C++,也能轻松与我们的平台 C 代码一起使用。本教程涵盖了如何在您的项目中开始使用 CppUTest。
在 SparkPost,我们投入了大量时间和精力来测试我们的代码。我们的平台是用 C 语言编写的,最近我研究了如何与一个名为 “CppUTest” 的单元测试框架集成,该框架为 C/C++ 提供 xUnit 风格的测试。这个框架功能强大、功能丰富,并且在积极开发中,因此是一个很好的选择。它还提供了一个 C 集成层,使得即使框架的大部分是 C++,也能轻松与我们的平台 C 代码一起使用。本教程涵盖了如何在您的项目中开始使用 CppUTest。
在 SparkPost,我们投入了大量时间和精力来测试我们的代码。我们的平台是用 C 语言编写的,最近我研究了如何与一个名为 “CppUTest” 的单元测试框架集成,该框架为 C/C++ 提供 xUnit 风格的测试。这个框架功能强大、功能丰富,并且在积极开发中,因此是一个很好的选择。它还提供了一个 C 集成层,使得即使框架的大部分是 C++,也能轻松与我们的平台 C 代码一起使用。本教程涵盖了如何在您的项目中开始使用 CppUTest。
正在下载 CppUTest
奠定基础
首先,让我们写一些代码!
我们的测试项目将有一个“main”文件,并将包含一个名为“code”的实用程序库。该库将提供一个简单的函数,返回1(目前)。文件的布局如下:
├── src │ ├── code │ │ ├── code.cpp │ │ └── code.h │ └── main.cpp └── t ├── main.cpp └── test.cpp
让我们从编写src/文件开始
// src/main.cpp #include <stdlib.h> #include <stdio.h> #include "code.h" int main(void) { test_func(); printf("hello world!\n"); exit(0); }
// src/code/code.cpp #include <stdlib.h> #include "code.h" int test_func() { return 1; }
// src/code/code.h #ifndef __code_h__ #define __code_h__ int test_func(); #endif
现在,让我们进行测试,这些测试将存放在t/目录中。首先要做的是设置一个测试运行器,它将运行我们的测试文件。这也是一次编译后将执行的‘main’函数:
// t/main.cpp #include "CppUTest/CommandLineTestRunner.h" int main(int ac, char** av) { return CommandLineTestRunner::RunAllTests(ac, av); }
现在我们可以编写第一个测试模块:
// t/test.cpp #include "CppUTest/TestHarness.h" #include "code.h" TEST_GROUP(AwesomeExamples) { }; TEST(AwesomeExamples, FirstExample) { int x = test_func(); CHECK_EQUAL(1, x); }
接下来,我们需要编写makefiles。我们需要两个:一个用于src/下的项目文件,一个用于测试。
首先,让我们写一些代码!
我们的测试项目将有一个“main”文件,并将包含一个名为“code”的实用程序库。该库将提供一个简单的函数,返回1(目前)。文件的布局如下:
├── src │ ├── code │ │ ├── code.cpp │ │ └── code.h │ └── main.cpp └── t ├── main.cpp └── test.cpp
让我们从编写src/文件开始
// src/main.cpp #include <stdlib.h> #include <stdio.h> #include "code.h" int main(void) { test_func(); printf("hello world!\n"); exit(0); }
// src/code/code.cpp #include <stdlib.h> #include "code.h" int test_func() { return 1; }
// src/code/code.h #ifndef __code_h__ #define __code_h__ int test_func(); #endif
现在,让我们进行测试,这些测试将存放在t/目录中。首先要做的是设置一个测试运行器,它将运行我们的测试文件。这也是一次编译后将执行的‘main’函数:
// t/main.cpp #include "CppUTest/CommandLineTestRunner.h" int main(int ac, char** av) { return CommandLineTestRunner::RunAllTests(ac, av); }
现在我们可以编写第一个测试模块:
// t/test.cpp #include "CppUTest/TestHarness.h" #include "code.h" TEST_GROUP(AwesomeExamples) { }; TEST(AwesomeExamples, FirstExample) { int x = test_func(); CHECK_EQUAL(1, x); }
接下来,我们需要编写makefiles。我们需要两个:一个用于src/下的项目文件,一个用于测试。
首先,让我们写一些代码!
我们的测试项目将有一个“main”文件,并将包含一个名为“code”的实用程序库。该库将提供一个简单的函数,返回1(目前)。文件的布局如下:
├── src │ ├── code │ │ ├── code.cpp │ │ └── code.h │ └── main.cpp └── t ├── main.cpp └── test.cpp
让我们从编写src/文件开始
// src/main.cpp #include <stdlib.h> #include <stdio.h> #include "code.h" int main(void) { test_func(); printf("hello world!\n"); exit(0); }
// src/code/code.cpp #include <stdlib.h> #include "code.h" int test_func() { return 1; }
// src/code/code.h #ifndef __code_h__ #define __code_h__ int test_func(); #endif
现在,让我们进行测试,这些测试将存放在t/目录中。首先要做的是设置一个测试运行器,它将运行我们的测试文件。这也是一次编译后将执行的‘main’函数:
// t/main.cpp #include "CppUTest/CommandLineTestRunner.h" int main(int ac, char** av) { return CommandLineTestRunner::RunAllTests(ac, av); }
现在我们可以编写第一个测试模块:
// t/test.cpp #include "CppUTest/TestHarness.h" #include "code.h" TEST_GROUP(AwesomeExamples) { }; TEST(AwesomeExamples, FirstExample) { int x = test_func(); CHECK_EQUAL(1, x); }
接下来,我们需要编写makefiles。我们需要两个:一个用于src/下的项目文件,一个用于测试。
Project Makefile
项目的 makefile 会与项目根目录下的 ‘src’ 和 ‘t’ 目录处于同一层级。它应如下所示:
# Makefile SRC_DIR = ./src CODE_DIR = $(SRC_DIR)/code OUT = example TEST_DIR = t test: make -C $(TEST_DIR) test_clean: make -C $(TEST_DIR) clean code.o: gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o main: code.o gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT) all: test main clean: test_clean rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)
请注意,这里对于测试目标使用了‘make -C’,这意味着它将再次使用测试目录中的 makefile 调用‘make’。
此时,我们可以使用 makefile 编译 ‘src’ 代码,并确保它正常工作:
[]$ make main gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example []$ ./example hello world
项目的 makefile 会与项目根目录下的 ‘src’ 和 ‘t’ 目录处于同一层级。它应如下所示:
# Makefile SRC_DIR = ./src CODE_DIR = $(SRC_DIR)/code OUT = example TEST_DIR = t test: make -C $(TEST_DIR) test_clean: make -C $(TEST_DIR) clean code.o: gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o main: code.o gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT) all: test main clean: test_clean rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)
请注意,这里对于测试目标使用了‘make -C’,这意味着它将再次使用测试目录中的 makefile 调用‘make’。
此时,我们可以使用 makefile 编译 ‘src’ 代码,并确保它正常工作:
[]$ make main gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example []$ ./example hello world
项目的 makefile 会与项目根目录下的 ‘src’ 和 ‘t’ 目录处于同一层级。它应如下所示:
# Makefile SRC_DIR = ./src CODE_DIR = $(SRC_DIR)/code OUT = example TEST_DIR = t test: make -C $(TEST_DIR) test_clean: make -C $(TEST_DIR) clean code.o: gcc -c -I$(CODE_DIR) $(CODE_DIR)/code.cpp -o $(CODE_DIR)/code.o main: code.o gcc -I$(CODE_DIR) $(CODE_DIR)/code.o $(SRC_DIR)/main.cpp -o $(OUT) all: test main clean: test_clean rm $(SRC_DIR)/*.o $(CODE_DIR)/*.o $(OUT)
请注意,这里对于测试目标使用了‘make -C’,这意味着它将再次使用测试目录中的 makefile 调用‘make’。
此时,我们可以使用 makefile 编译 ‘src’ 代码,并确保它正常工作:
[]$ make main gcc -c -I./src/code ./src/code/code.cpp -o ./src/code/code.o gcc -I./src/code ./src/code/code.o ./src/main.cpp -o example []$ ./example hello world
Tests Makefile
对于测试,由于我们需要正确加载并集成 CppUTest 库,事情稍微复杂一些。
CppUTest 仓库提供了一个名为“MakefileWorker.mk”的文件。它提供了许多功能,使得使用 CppUTest 构建变得简单。该文件位于 git 仓库的“build”目录下。在本教程中,我们假设它已被复制到 't/' 目录中。可以按如下方式使用:
# we don’t want to use relative paths, so we set these variables PROJECT_DIR=/path/to/project SRC_DIR=$(PROJECT_DIR)/src TEST_DIR=$(PROJECT_DIR)/t # specify where the source code and includes are located INCLUDE_DIRS=$(SRC_DIR)/code SRC_DIRS=$(SRC_DIR)/code # specify where the test code is located TEST_SRC_DIRS=$(TEST_DIR) # what to call the test binary TEST_TARGET=example # where the cpputest library is located CPPUTEST_HOME=/usr/local # run MakefileWorker.mk with the variables defined here include MakefileWorker.mk
请注意,CPPUTEST_HOME 必须设置为 CppUTest 安装的位置。如果您安装了发行版本包,这通常位于 linux/mac 系统上的 /usr/local 下。如果您自己检出过仓库,则为检出的所在位置。
这些选项都在 MakefileWorker.mk 中进行了文档说明。
MakefileWorker.mk 还添加了一些 makefile 目标,包括以下内容:
all – 构建由 makefile 指定的测试
clean – 删除为测试生成的所有对象和 gcov 文件
realclean – 删除整个目录树中的所有对象或 gcov 文件
flags – 列出用于编译测试的所有配置标志
debug – 列出所有源文件、对象、依赖关系和“要清理的东西”
对于测试,由于我们需要正确加载并集成 CppUTest 库,事情稍微复杂一些。
CppUTest 仓库提供了一个名为“MakefileWorker.mk”的文件。它提供了许多功能,使得使用 CppUTest 构建变得简单。该文件位于 git 仓库的“build”目录下。在本教程中,我们假设它已被复制到 't/' 目录中。可以按如下方式使用:
# we don’t want to use relative paths, so we set these variables PROJECT_DIR=/path/to/project SRC_DIR=$(PROJECT_DIR)/src TEST_DIR=$(PROJECT_DIR)/t # specify where the source code and includes are located INCLUDE_DIRS=$(SRC_DIR)/code SRC_DIRS=$(SRC_DIR)/code # specify where the test code is located TEST_SRC_DIRS=$(TEST_DIR) # what to call the test binary TEST_TARGET=example # where the cpputest library is located CPPUTEST_HOME=/usr/local # run MakefileWorker.mk with the variables defined here include MakefileWorker.mk
请注意,CPPUTEST_HOME 必须设置为 CppUTest 安装的位置。如果您安装了发行版本包,这通常位于 linux/mac 系统上的 /usr/local 下。如果您自己检出过仓库,则为检出的所在位置。
这些选项都在 MakefileWorker.mk 中进行了文档说明。
MakefileWorker.mk 还添加了一些 makefile 目标,包括以下内容:
all – 构建由 makefile 指定的测试
clean – 删除为测试生成的所有对象和 gcov 文件
realclean – 删除整个目录树中的所有对象或 gcov 文件
flags – 列出用于编译测试的所有配置标志
debug – 列出所有源文件、对象、依赖关系和“要清理的东西”
对于测试,由于我们需要正确加载并集成 CppUTest 库,事情稍微复杂一些。
CppUTest 仓库提供了一个名为“MakefileWorker.mk”的文件。它提供了许多功能,使得使用 CppUTest 构建变得简单。该文件位于 git 仓库的“build”目录下。在本教程中,我们假设它已被复制到 't/' 目录中。可以按如下方式使用:
# we don’t want to use relative paths, so we set these variables PROJECT_DIR=/path/to/project SRC_DIR=$(PROJECT_DIR)/src TEST_DIR=$(PROJECT_DIR)/t # specify where the source code and includes are located INCLUDE_DIRS=$(SRC_DIR)/code SRC_DIRS=$(SRC_DIR)/code # specify where the test code is located TEST_SRC_DIRS=$(TEST_DIR) # what to call the test binary TEST_TARGET=example # where the cpputest library is located CPPUTEST_HOME=/usr/local # run MakefileWorker.mk with the variables defined here include MakefileWorker.mk
请注意,CPPUTEST_HOME 必须设置为 CppUTest 安装的位置。如果您安装了发行版本包,这通常位于 linux/mac 系统上的 /usr/local 下。如果您自己检出过仓库,则为检出的所在位置。
这些选项都在 MakefileWorker.mk 中进行了文档说明。
MakefileWorker.mk 还添加了一些 makefile 目标,包括以下内容:
all – 构建由 makefile 指定的测试
clean – 删除为测试生成的所有对象和 gcov 文件
realclean – 删除整个目录树中的所有对象或 gcov 文件
flags – 列出用于编译测试的所有配置标志
debug – 列出所有源文件、对象、依赖关系和“要清理的东西”
代码覆盖率
单元测试如果没有覆盖率报告就不完整。对于使用gcc的项目,首选工具是gcov,这是标准gcc工具套件的一部分。Cpputest可以轻松与gcov集成,您只需要在makefile中添加这一行:
CPPUTEST_USE_GCOV=Y
接下来,我们需要确保此仓库中的filterGcov.sh脚本位于相对于您设置的‘CPPUTEST_HOME’的‘/scripts/filterGcov.sh’。它还需要有执行权限。
在示例Makefile中,它将被部署到‘/usr/local/scripts/filterGcov.sh’。如果您从仓库签出运行CppUTest,一切应该无需修改。
在此基础上,您只需运行‘make gcov’,分析就会为您生成。在我们的例子中,我们需要运行‘make -B’来重新构建启用gcov的对象文件:
[]$ make -B gcov < compilation output > for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \ FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \ gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \ done for f in ; do \ gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \ done /usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt cat gcov_report.txt 100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp mkdir -p gcov mv *.gcov gcov mv gcov_* gcov See gcov directory for details
这将输出许多文件到一个新的‘gcov’目录。这些包括:
code.cpp.gcov – 被测试代码的实际‘gcov’文件
gcov_error.txt – 错误报告(在我们的例子中,它应该是空的)
gcov_output.txt – 运行的gcov命令的实际输出
gcov_report.txt – 每个测试文件下的覆盖率摘要
gcov_report.txt.html – gcov_report的html版本
单元测试如果没有覆盖率报告就不完整。对于使用gcc的项目,首选工具是gcov,这是标准gcc工具套件的一部分。Cpputest可以轻松与gcov集成,您只需要在makefile中添加这一行:
CPPUTEST_USE_GCOV=Y
接下来,我们需要确保此仓库中的filterGcov.sh脚本位于相对于您设置的‘CPPUTEST_HOME’的‘/scripts/filterGcov.sh’。它还需要有执行权限。
在示例Makefile中,它将被部署到‘/usr/local/scripts/filterGcov.sh’。如果您从仓库签出运行CppUTest,一切应该无需修改。
在此基础上,您只需运行‘make gcov’,分析就会为您生成。在我们的例子中,我们需要运行‘make -B’来重新构建启用gcov的对象文件:
[]$ make -B gcov < compilation output > for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \ FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \ gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \ done for f in ; do \ gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \ done /usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt cat gcov_report.txt 100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp mkdir -p gcov mv *.gcov gcov mv gcov_* gcov See gcov directory for details
这将输出许多文件到一个新的‘gcov’目录。这些包括:
code.cpp.gcov – 被测试代码的实际‘gcov’文件
gcov_error.txt – 错误报告(在我们的例子中,它应该是空的)
gcov_output.txt – 运行的gcov命令的实际输出
gcov_report.txt – 每个测试文件下的覆盖率摘要
gcov_report.txt.html – gcov_report的html版本
单元测试如果没有覆盖率报告就不完整。对于使用gcc的项目,首选工具是gcov,这是标准gcc工具套件的一部分。Cpputest可以轻松与gcov集成,您只需要在makefile中添加这一行:
CPPUTEST_USE_GCOV=Y
接下来,我们需要确保此仓库中的filterGcov.sh脚本位于相对于您设置的‘CPPUTEST_HOME’的‘/scripts/filterGcov.sh’。它还需要有执行权限。
在示例Makefile中,它将被部署到‘/usr/local/scripts/filterGcov.sh’。如果您从仓库签出运行CppUTest,一切应该无需修改。
在此基础上,您只需运行‘make gcov’,分析就会为您生成。在我们的例子中,我们需要运行‘make -B’来重新构建启用gcov的对象文件:
[]$ make -B gcov < compilation output > for d in /Users/ykuperman/code/blogpost/qa/src/code ; do \ FILES=`ls $d/*.c $d/*.cc $d/*.cpp 2> /dev/null` ; \ gcov --object-directory objs/$d $FILES >> gcov_output.txt 2>>gcov_error.txt ; \ done for f in ; do \ gcov --object-directory objs/$f $f >> gcov_output.txt 2>>gcov_error.txt ; \ done /usr/local/scripts/filterGcov.sh gcov_output.txt gcov_error.txt gcov_report.txt example.txt cat gcov_report.txt 100.00% /Users/ykuperman/code/blogpost/qa/src/code/code.cpp mkdir -p gcov mv *.gcov gcov mv gcov_* gcov See gcov directory for details
这将输出许多文件到一个新的‘gcov’目录。这些包括:
code.cpp.gcov – 被测试代码的实际‘gcov’文件
gcov_error.txt – 错误报告(在我们的例子中,它应该是空的)
gcov_output.txt – 运行的gcov命令的实际输出
gcov_report.txt – 每个测试文件下的覆盖率摘要
gcov_report.txt.html – gcov_report的html版本
Cpputest Memory Leak 检测
Cpputest 通过重新定义标准的 “malloc/free” 函数族,使用自己的包装器来自动检测内存泄漏。这使得它可以快速捕捉泄漏并在每次测试执行时报告它们。在 MakefileWorker.mk 中默认启用,所以根据前述步骤已经是开启的。
为了说明这一点,让我们在 test_func() 中泄漏一些内存 !
回到 code.c 中,我们向函数添加一个 malloc() ,如下所示:
int test_func() { malloc(1); return 1; }
现在,重新编译后出现如下错误:
test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample) Memory leak(s) found. Alloc num (4) Leak size: 1 Allocated at: ./code.c and line: 6 Type: "malloc" Memory: <
这显示了是哪个测试引起了泄漏、源代码中泄漏发生的位置以及泄漏内存中的内容。这真的很有帮助!
此功能有几点注意事项:
Cpputest 使用预处理器宏动态重定义所有对标准内存管理函数的调用。这意味着它只适用于测试中的源代码调用,因为这是与 CppUTest 的覆盖功能一起编译的。链接库中的泄漏将不会被捕获。
有时候,分配给整个进程生命周期的内存并不打算被释放。如果你测试一个具有此行为的模块,这可能会导致大量错误信息。要禁用泄漏检测,可以这样做:
CPPUTEST_USE_MEM_LEAK_DETECTION=N
Cpputest 通过重新定义标准的 “malloc/free” 函数族,使用自己的包装器来自动检测内存泄漏。这使得它可以快速捕捉泄漏并在每次测试执行时报告它们。在 MakefileWorker.mk 中默认启用,所以根据前述步骤已经是开启的。
为了说明这一点,让我们在 test_func() 中泄漏一些内存 !
回到 code.c 中,我们向函数添加一个 malloc() ,如下所示:
int test_func() { malloc(1); return 1; }
现在,重新编译后出现如下错误:
test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample) Memory leak(s) found. Alloc num (4) Leak size: 1 Allocated at: ./code.c and line: 6 Type: "malloc" Memory: <
这显示了是哪个测试引起了泄漏、源代码中泄漏发生的位置以及泄漏内存中的内容。这真的很有帮助!
此功能有几点注意事项:
Cpputest 使用预处理器宏动态重定义所有对标准内存管理函数的调用。这意味着它只适用于测试中的源代码调用,因为这是与 CppUTest 的覆盖功能一起编译的。链接库中的泄漏将不会被捕获。
有时候,分配给整个进程生命周期的内存并不打算被释放。如果你测试一个具有此行为的模块,这可能会导致大量错误信息。要禁用泄漏检测,可以这样做:
CPPUTEST_USE_MEM_LEAK_DETECTION=N
Cpputest 通过重新定义标准的 “malloc/free” 函数族,使用自己的包装器来自动检测内存泄漏。这使得它可以快速捕捉泄漏并在每次测试执行时报告它们。在 MakefileWorker.mk 中默认启用,所以根据前述步骤已经是开启的。
为了说明这一点,让我们在 test_func() 中泄漏一些内存 !
回到 code.c 中,我们向函数添加一个 malloc() ,如下所示:
int test_func() { malloc(1); return 1; }
现在,重新编译后出现如下错误:
test.cpp:9: error: Failure in TEST(AwesomeExamples, FirstExample) Memory leak(s) found. Alloc num (4) Leak size: 1 Allocated at: ./code.c and line: 6 Type: "malloc" Memory: <
这显示了是哪个测试引起了泄漏、源代码中泄漏发生的位置以及泄漏内存中的内容。这真的很有帮助!
此功能有几点注意事项:
Cpputest 使用预处理器宏动态重定义所有对标准内存管理函数的调用。这意味着它只适用于测试中的源代码调用,因为这是与 CppUTest 的覆盖功能一起编译的。链接库中的泄漏将不会被捕获。
有时候,分配给整个进程生命周期的内存并不打算被释放。如果你测试一个具有此行为的模块,这可能会导致大量错误信息。要禁用泄漏检测,可以这样做:
CPPUTEST_USE_MEM_LEAK_DETECTION=N
感兴趣?
这只是冰山一角,这个工具包含的所有功能远不止于此。除了这里讨论的基础知识之外,它还具有一个mock框架、一个直接的C集成层和一个插件框架,仅举几个重要的功能。这个repo还包含一个完整的帮助手册目录,可以帮助自动化处理框架中的一些日常工作部分。
我希望这里的信息能帮助您使用这个出色的工具提高您的C/C++代码质量!
这只是冰山一角,这个工具包含的所有功能远不止于此。除了这里讨论的基础知识之外,它还具有一个mock框架、一个直接的C集成层和一个插件框架,仅举几个重要的功能。这个repo还包含一个完整的帮助手册目录,可以帮助自动化处理框架中的一些日常工作部分。
我希望这里的信息能帮助您使用这个出色的工具提高您的C/C++代码质量!
这只是冰山一角,这个工具包含的所有功能远不止于此。除了这里讨论的基础知识之外,它还具有一个mock框架、一个直接的C集成层和一个插件框架,仅举几个重要的功能。这个repo还包含一个完整的帮助手册目录,可以帮助自动化处理框架中的一些日常工作部分。
我希望这里的信息能帮助您使用这个出色的工具提高您的C/C++代码质量!



