news 2026/4/18 5:26:31

cmake应用:集成gtest进行单元测试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
cmake应用:集成gtest进行单元测试

🍅点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快

编写代码有bug是很正常的,通过编写完备的单元测试,可以及时发现问题,并且在后续的代码改进中持续观测是否引入了新的bug。对于追求质量的程序员,为自己的代码编写全面的单元测试是必备的基础技能,在编写单元测试的时候也能复盘自己的代码设计,是提高代码质量极为有效的手段。

本文主要介绍以下几个方面的内容:

1、何为单元测试

2、何为gtest

3、怎么使用gtest

4、怎么运行测试

一、单元测试是什么?

单元测试(Unit Testing),一般指对软件中的最小可测试单元进行检查和验证。最小可测试单元可以是指一个函数、一次调用过程、一个类等,不同的语言可能有不同的测试方法,暂时不必深究。

对于C/C++语言,单元测试一般是针对一个函数而言,单元测试的目的就是检测目标函数在所有可能的输入下,函数的执行过程和输出是否符合预期。可以说,单元测试是颗粒度最小的测试,对于软件开发而言,保证每个小的函数执行正确,才能保证利用这些小模块组合起来的系统能够正常工作。

和测试相关的另外一个重要概念是测试用例(Test Case)。百度百科给的定义是,测试用例是对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略,包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等。

这个定义是比较广泛的,对于单元测试来说,就是测试在不同输入下,目标函数(模块)的预期执行过程和输出(返回值),每个不同的情形可以有一个或多个测试用例。编写测试用例需要尽量覆盖所有输入情况(尤其是边界值、特殊值、异常值)。比如下列函数:

int fibo(int i) { if (i == 1 || i == 2) { return 1; } return fibo(i - 1) + fibo(i - 2); }

这个函数是为了实现斐波那契数列,所以输入可以分为几类,就可以覆盖所有情况:

1. 小于等于0的整数

2. 1和2

3. 大于2的整数

对应地,可以设置以下测试用例:

1. 输入0,期望值是0

2. 输入1,期望值是1

3. 输入2,期望值是1

4. 输入3,期望值是2

5. 输入4,期望值是3

可以比较明显地发现,如果输入是小于等于0的整数,这个函数就一直递归下去了。这也是开发过程中需要注意的,代码(功能)的使用者并不一定会遵循常规的思维(斐波那契数列不可能输入负数),开发者只能相信自己的代码,不要对输入有任何假设。

上述test case在cmake-template项目的test/c/test_gtest_demo.cc中有示例

二、gtest简介

Google Test是Google开源的一个跨平台的C++单元测试框架,简称gtest,它提供了非常丰富的测试断言、判断宏,极大方便开发者编写测试用例的流程,也是很多开源项目使用的测试框架。

在前面介绍CMake的测试功能时,每个单元测试都是一个可执行文件,实现了main函数,在CMakeLists.txt中使用add_test命令来添加测试用例:

enable_testing() add_executable(test_add test/c/test_add.c) add_executable(test_minus test/c/test_minus.c) target_link_libraries(test_add math) target_link_libraries(test_minus math) add_test(NAME test_add COMMAND test_add 10 24 34) add_test(NAME test_minus COMMAND test_minus 40 96 -56)

通过使用gtest可以简化这个流程,让开发者可以专注在测试用例的书写上,而不用手动编写大量的main函数,以及一些判断输出是否符合预期的附加代码。

三、集成gtest

1、将gtest源码加入项目

gtest是一个开源的框架,代码位于github仓库:google/googletest,本文介绍直接将gtest加入到项目中,通过CMake编译使用。

首先在项目根目录新建一个third_party目录,下载源码的最新release版本,并解压:

# mkdir third_party # cd third_party # wget https://codeload.github.com/google/googletest/zip/refs/tags/release-1.10.0 # unzip googletest-release-1.10.0.zip

2、将gtest添加为子模块

修改项目根目录的CMakeLists.txt文件,使用上一篇文章介绍的命令add_subdirectory,在开启单元测试时,添加gtest为子模块,并将对应头文件路径添加进来:

enable_testing() add_subdirectory(third_party/googletest-release-1.10.0) include_directories(third_party/googletest-release-1.10.0/googletest/include)

此时执行命令:

# cmake -B cmake-build # cmake --build cmake-build

可以看到构建目录下多了一个目录cmake-build/third_party/googletest-release-1.10.0,并且gtest编译生成了4个新的库文件(gtest子模块的编译目标,位于目录cmake-build/lib下):

1. libgtest.a

2. libgtest_main.a

3. libgmock.a

4. libgmock_main.a

其中libgtest.a提供单元测试相关的功能,libgtest_main.a提供单元测试的主入口,只有链接该库,测试用例就会编译成可执行文件;两个mock库也是类似的,主要提供数据库交互,网络连接等方面的模拟测试,这不是本文的重点。

此时就可以在链接其他目标时直接使用gtest的这4个编译目标(target)。

3、编写测试用例

接下来直接修改先前的两个测试用例源文件,实现相同的测试功能:

1. test/c/test_add.c

2. test/c/test_minus.c

因为使用的是C++测试框架,所以上述两个源文件修改为.cc后缀。

在源文件中include头文件gtest/gtest.h,使用gtest测试用例定义宏来定义测试用例:

TEST(test_case_name, test_name) {}

一个test_case_name下面可以包含多个不同(test_name)的测试。

test/c/test_add.cc内容为:

#include "gtest/gtest.h" #include "math/add.h" TEST(TestAddInt, test_add_int_1) { int res = add_int(10, 24); EXPECT_EQ(res, 34); }

test/c/test_minus.cc内容为:

#include "gtest/gtest.h" #include "math/minus.h" TEST(TestMinusInt, test_minus_int_1) { int res = minus_int(40, 96); EXPECT_EQ(res, -56); }

显而易见,测试用例的代码量比之前少了很多,而且更加可读,更加专业。

这里使用了一个判断值相等的断言EXPECT_EQ,gtest中的断言分成两大类:

1. ASSERT_*系列:如果检测失败就直接退出当前函数

2. EXPECT_*系列:如果检测失败发出提示,并继续往下执行

gtest有很多类似的宏用来判断数值的关系、判断条件的真假、判断字符串的关系。 对于条件判断可以使用:

ASSERT_TRUE(condition); // 判断条件是否为真

ASSERT_FALSE(condition); // 判断条件是否为假

对于数值比较可以使用:

ASSERT_EQ(val1, val2); // 判断是否相等

ASSERT_NE(val1, val2); // 判断是否不相等

ASSERT_LT(val1, val2); // 判断是否小于

ASSERT_LE(val1, val2); // 判断是否小于等于

ASSERT_GT(val1, val2); // 判断是否大于

ASSERT_GE(val1, val2); // 判断是否大于等于

对于字符串比较可以使用:

ASSERT_STREQ(str1,str2); // 判断字符串是否相等

ASSERT_STRNE(str1,str2); // 判断字符串是否不相等

ASSERT_STRCASEEQ(str1,str2); // 判断字符串是否相等,忽视大小写

ASSERT_STRCASENE(str1,str2); // 判断字符串是否不相等,忽视大小写

4、添加测试用例

书写好测试用例源文件后,需要修改项目根目录的CMakeLists.txt:

enable_testing() add_subdirectory(third_party/googletest-release-1.10.0) include_directories(third_party/googletest-release-1.10.0/googletest/include) set(GTEST_LIB gtest gtest_main) add_executable(test_add test/c/test_add.cc) add_executable(test_minus test/c/test_minus.cc) target_link_libraries(test_add math gtest gtest_main) target_link_libraries(test_minus math gtest gtest_main) add_test(NAME test_add COMMAND test_add) add_test(NAME test_minus COMMAND test_minus)

对于一个单元测试来说,添加的步骤为:

1. 使用add_executable添加测试目标

2. 使用target_link_libraries为测试目标添加依赖gtest和gtest_main

3. 使用add_test添加到项目,以便可以使用ctest命令执行测试

需要注意的不同就是,依旧将单元测试的源文件编译为可执行文件,并且链接的时候链接了gtest和gtest_main。必须要链接gtest_main库,才能给单元测试添加main函数主入口,否则在链接的时候将会报错。

5、运行测试

在前面的文章中已经介绍过了,在构建编译完成后,进入构建目录,使用ctest命令执行测试即可。 笔者常用的命令为:

make test CTEST_OUTPUT_ON_FAILURE=TRUE GTEST_COLOR=TRUE # 或者 GTEST_COLOR=TRUE ctest --output-on-failure

指定--output-on-failure或者设置CTEST_OUTPUT_ON_FAILURE变量为TRUE,让单元测试失败时输出具体信息,而GTEST_COLOR设置为TRUE可以让输出带有颜色,可以在详细输出模式下(-VV)更快找到错误的输出(如果有失败的测试)。

这里的单元测试也只是作为示例,在真实的项目中,单元测试的编写往往更加复杂,而且这也还只是提高的软件鲁棒性中的一环,追求极致还需要更多努力。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 5:19:26

Kafka Consumer消费延迟(Lag)飙升,如何快速止血?

Kafka作为现代分布式系统的核心组件,其高吞吐、低延迟的特性被广泛应用于实时数据处理场景。当Consumer消费延迟(Lag)突然飙升时,可能导致数据积压、业务告警甚至服务雪崩。如何快速定位问题并止血,成为开发者必须掌握…

作者头像 李华
网站建设 2026/4/18 5:19:17

JeecgBoot-Uniapp

这个项目的目录结构是标准的 Vite Vue3 TS 架构,它比传统的 uni-app 项目更接近 Vue3 官方的开发体验。JeecgUniapp/ ├── src/ │ ├── api/ # 所有的接口定义,按模块分类(如 sys.ts, user.ts) │ ├── c…

作者头像 李华
网站建设 2026/4/18 5:18:15

040、专栏总结与展望:YOLO系列的未来与工业落地实践

深夜的实验室,示波器上跳动的波形映在屏幕上,我盯着眼前这块嵌入式板卡,YOLOv11的推理结果时准时不准。输出张量的内存对齐出了问题——又是那些“理论上成立,部署时崩盘”的细节。这让我想起这些年跟YOLO系列打交道的日子&#x…

作者头像 李华
网站建设 2026/4/18 5:15:41

从B站Sign算法看移动端API安全:如何用IDA Pro快速定位关键Native函数

移动端API安全逆向实战:B站Sign算法深度解析与IDA Pro高阶技巧 1. Native层安全机制逆向分析的价值与挑战 在移动应用安全领域,Native层代码逆向分析正成为攻防对抗的前沿阵地。根据Veracode最新研究报告,超过83%的主流移动应用将核心安全逻辑…

作者头像 李华
网站建设 2026/4/18 5:15:38

Inkscape:从零上手到高效出图的实用指南(附最新版获取方式)

1. 为什么选择Inkscape作为你的第一把矢量设计利器 第一次接触矢量设计软件时,我也曾在众多选项中犹豫不决。直到偶然发现Inkscape这个开源神器,才真正体会到什么叫"小而美"。作为一款完全免费的矢量图形编辑软件,它不仅具备专业级…

作者头像 李华
网站建设 2026/4/18 5:14:45

芸众商城开源版2025最新版:从零搭建到多插件配置全指南

1. 芸众商城开源版2025核心特性解析 芸众商城2025开源版作为社交电商领域的标杆解决方案,最让我惊艳的是它模块化架构设计带来的灵活扩展性。这个版本采用微服务架构,将用户中心、商品管理、订单处理等核心功能拆分为独立服务,开发者可以根据…

作者头像 李华