当前位置: 首页 > news >正文

【020】使用Google Test进行 C++ 单元测试:基于 CMake 和 FetchContent 的现代方法

文章目录

  • 一、前言
  • 二、准备工作
  • 三、配置CMakeLists.txt
  • 四、构建与测试
  • 五、工作原理深度解析
  • 六、更多信息与替代方案

一、前言

在现代C++项目开发中,单元测试是确保代码质量和可维护性的关键环节。Google Test(GTest)作为一款功能强大、广受欢迎的C++测试框架,提供了丰富的断言、测试夹具和测试发现机制。

在这里插入图片描述

本文演示如何利用CMake的FetchContent模块,优雅地集成和使用Google Test进行单元测试。不仅会展示具体步骤,还会深入探讨FetchContent的工作原理,并提及它与ExternalProject_Add的区别,帮助更好地理解其在项目管理中的优势。

二、准备工作

在开始集成Google Test之前,需要准备一些待测试的 C++ 代码以及相应的测试用例。

以一个简单的整数求和函数为例。

  • sum_integers.hpp: 头文件,声明求和函数。
  • sum_integers.cpp: 源文件,实现求和函数。
  • main.cpp: 主应用程序文件,用于演示如何使用 sum_integers 库。

sum_integers.hpp

#ifndef SUM_INTEGERS_HPP
#define SUM_INTEGERS_HPP#include <numeric>
#include <vector>
/*** @brief Calculates the sum of integers in a given range.* @param integers An initializer list of integers.* @return The sum of the integers.*/
long long sum_integers(std::initializer_list<int> integers);#endif // SUM_INTEGERS_HPP

sum_integers.cpp

#include "sum_integers.hpp"
#include <numeric> // For std::accumulatelong long sum_integers(std::initializer_list<int> integers) 
{long long sum = 0;for (int i : integers) {sum += i;}return sum;// Alternatively, using std::accumulate:// return std::accumulate(integers.begin(), integers.end(), 0LL);
}

main.cpp

#include "sum_integers.hpp"
#include <iostream>
#include <vector>int main() 
{std::initializer_list<int> numbers1 = {1, 2, 3, 4, 5};long long result1 = sum_integers(numbers1);std::cout << "Sum of {1, 2, 3, 4, 5} = " << result1 << std::endl; // Expected: 15std::initializer_list<int> numbers2 = {10, -5, 2, -7};long long result2 = sum_integers(numbers2);std::cout << "Sum of {10, -5, 2, -7} = " << result2 << std::endl; // Expected: 0return 0;
}

Google Test测试用例 (test.cpp): test.cpp 文件包含单元测试代码。它会包含 sum_integers.hpp 来访问待测试函数,并包含 gtest/gtest.h 来使用Google Test框架。

#include "sum_integers.hpp" // 包含待测试函数的头文件
#include "gtest/gtest.h"    // 包含Google Test框架的头文件
#include <vector>// Google Test的入口点。
// 这是所有Google Test可执行文件都需要的标准main函数。
int main(int argc, char **argv) {// 初始化Google Test框架。它会解析命令行参数,并设置测试环境。::testing::InitGoogleTest(&argc, argv);// 运行所有定义的测试。return RUN_ALL_TESTS();
}// 定义一个测试套件(Test Suite)名为 'example',其中包含一个测试用例 'sum_zero'。
TEST(example, sum_zero) {// 定义一个整数列表,其和为0。auto integers = {1, -1, 2, -2, 3, -3};// 调用待测试函数。auto result = sum_integers(integers);// 使用ASSERT_EQ断言验证结果是否等于预期值0。// 如果不相等,测试将立即失败,并终止当前测试函数。ASSERT_EQ(result, 0);
}// 定义另一个测试用例 'sum_five',属于 'example' 测试套件。
TEST(example, sum_five) {// 定义一个整数列表,其和为15。auto integers = {1, 2, 3, 4, 5};// 调用待测试函数。auto result = sum_integers(integers);// 使用ASSERT_EQ断言验证结果是否等于预期值15。ASSERT_EQ(result, 15);
}

与将Google Test的源代码直接放入项目仓库不同,利用CMake的FetchContent模块在配置时自动下载并构建Google Test,从而保持项目自身的轻量级。

三、配置CMakeLists.txt

以下步骤详细描述了如何设置 CMakeLists.txt 文件,以使用Google Test编译测试可执行文件。

CMakeLists.txt

# 设置CMake的最低版本要求。FetchContent模块从3.11版本开始可用。
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)# 定义项目名称和使用的语言。
project(recipe-22 LANGUAGES CXX)# 设置C++标准为C++11。
set(CMAKE_CXX_STANDARD 11)
# 禁用C++编译器扩展(推荐,以确保代码的可移植性)。
set(CMAKE_CXX_EXTENSIONS OFF)
# 强制要求使用指定的C++标准。
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 针对Windows平台,如果需要导出符号,可以设置此选项。
# 这通常用于构建DLL时,确保所有公共符号都被导出。
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)# 1. 定义我们的库:sum_integers
# add_library命令用于创建静态或动态库。
add_library(sum_integers sum_integers.cpp)# 2. 定义主应用程序可执行文件
# add_executable命令用于创建可执行文件。
add_executable(sum_up main.cpp)
# target_link_libraries命令用于将库链接到可执行文件或另一个库。
# sum_up 可执行文件需要链接 sum_integers 库。
target_link_libraries(sum_up sum_integers)# 3. 启用/禁用单元测试的选项
# option命令用于定义一个用户可配置的选项,默认值为ON。
option(ENABLE_UNIT_TESTS "Enable unit tests" ON)
# message命令用于在CMake配置过程中输出信息。
message(STATUS "Unit tests enabled: ${ENABLE_UNIT_TESTS}")# 只有当ENABLE_UNIT_TESTS为ON时,才执行后续与测试相关的CMake代码。
if(ENABLE_UNIT_TESTS)# 4. 引入FetchContent模块# FetchContent模块允许在配置时下载外部项目。include(FetchContent)# 5. 声明要获取的Google Test项目# FetchContent_Declare用于声明一个外部内容源。FetchContent_Declare(googletest # 外部项目的名称,后续会用到这个名称来引用它。GIT_REPOSITORY https://github.com/google/googletest.git # Git仓库URL。GIT_TAG release-1.8.0 # 指定要下载的Git标签或提交哈希,确保版本一致性。# GIT_SHALLOW TRUE # 可选:进行浅克隆,减少下载时间。)# 6. 查询Google Test项目是否已被填充# FetchContent_GetProperties用于获取已声明内容的属性,# 例如是否已被下载和配置(POPULATED)。FetchContent_GetProperties(googletest)# 7. 如果Google Test尚未被填充,则进行下载和配置if(NOT googletest_POPULATED)# FetchContent_Populate用于执行下载和解压操作。# 它会设置 ${googletest_SOURCE_DIR} 和 ${googletest_BINARY_DIR} 变量。FetchContent_Populate(googletest)# 针对Visual Studio的特定配置:# 强制Google Test使用共享运行时库(CRT),以避免与主项目不一致。set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)# 禁用Google Test使用PThreads,避免潜在的冲突或不必要的依赖。set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)# 将下载的Google Test项目添加为当前项目的一个子目录。# 这会处理Google Test自身的CMakeLists.txt,并使其内部定义的target可用。# 例如,它会定义 gtest, gtest_main, gmock, gmock_main 等目标。add_subdirectory(${googletest_SOURCE_DIR} # Google Test的源代码目录。${googletest_BINARY_DIR} # Google Test的构建目录。)# 针对MSVC编译器的特定警告处理:# 解决在MSVC下编译Google Test时可能出现的std::tr1命名空间弃用警告。if(MSVC)foreach(_tgt gtest gtest_main gmock gmock_main)target_compile_definitions(${_tgt}PRIVATE"_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING")endforeach()endif()endif()# 8. 定义单元测试可执行文件# 创建一个名为 cpp_test 的可执行文件。add_executable(cpp_test "") # 初始为空,后续通过target_sources添加源文件。# 9. 指定测试可执行文件的源文件# target_sources命令用于向目标添加源文件。target_sources(cpp_testPRIVATE # PRIVATE表示这些源文件仅用于构建此目标,不影响其他目标。test.cpp # 我们的测试用例文件。)# 10. 链接测试可执行文件所需的库# cpp_test 需要链接 sum_integers 库(因为它测试这个库)# 还需要链接 gtest_main 库,这是Google Test提供的包含main函数的库。target_link_libraries(cpp_testPRIVATEsum_integers # 链接我们自己定义的库。gtest_main   # 链接Google Test的主库,它包含了测试运行器。)# 11. 启用并添加测试到CTest# enable_testing() 必须在 add_test() 之前调用,以启用CTest测试发现。enable_testing()# add_test命令用于向CTest注册一个测试。add_test(NAME google_test # 测试的名称,在ctest输出中显示。COMMAND $<TARGET_FILE:cpp_test> # 运行测试的命令,这里使用CMake生成的可执行文件路径。)
endif()

要注意,CMake 3.11才能使用FetchContent模块。

引入了一个检查ENABLE_UNIT_TESTS的判断。目的是在没有网络连接时,也能使用Google Test。

四、构建与测试

完成 CMakeLists.txt 的配置后,可以开始构建和运行测试了。

  1. 创建构建目录并进入: 建议在项目根目录外创建一个独立的 build 目录,以保持源代码目录的整洁。

    mkdir -p build
    cd build
    
  2. 配置项目: 运行 cmake .. 命令来配置项目。这将触发 FetchContent 下载 Google Test。

    cmake ..
    

    在配置过程中,会看到类似以下输出,表明Google Test正在被下载和配置:

    -- The CXX compiler identification is GNU 11.4.0
    -- The C compiler identification is GNU 11.4.0
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Check for working CXX compiler: /usr/bin/c++ - skipped
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Check for working C compiler: /usr/bin/cc - skipped
    -- Unit tests enabled: ON
    -- Fetching googletest
    -- Performing download step (git clone) for 'googletest'
    -- googletest-src/CMakeLists.txt
    -- ... (Google Test自身的配置输出) ...
    -- Configuring done
    -- Generating done
    
  3. 构建项目: 运行 cmake --build . 命令来编译所有目标,包括主应用程序和测试可执行文件。

    cmake --build .
    
  4. 运行单元测试 (使用 CTest): CTest 是 CMake 的测试运行器,它会发现并执行 add_test 定义的所有测试。

    ctest
    

    输出:

    Test project /home/fly/workspace/cmake-learning-code/recipe_22_gtest/build
    Start 1: google_test
    1/1 Test #1: google_test ......................   Passed    0.00 sec100% tests passed, 0 tests failed out of 1Total Test time (real) =   0.01 sec
    
  5. 直接运行测试可执行文件: 也可以直接运行由Google Test生成的测试可执行文件 cpp_test,它会提供Google Test自身更详细的输出。

    ./cpp_test
    

    输出:

    [==========] Running 2 tests from 1 test case.
    [----------] Global test environment set-up.
    [----------] 2 tests from example
    [ RUN      ] example.sum_zero
    [       OK ] example.sum_zero (0 ms)
    [ RUN      ] example.sum_five
    [       OK ] example.sum_five (0 ms)
    [----------] 2 tests from example (0 ms total)[----------] Global test environment tear-down
    [==========] 2 tests from 1 test case ran. (0 ms total)
    [  PASSED  ] 2 tests.
    

五、工作原理深度解析

FetchContent 模块是CMake 3.11版本引入的一个强大功能,它允许在CMake的配置阶段下载外部项目。这与传统的 ExternalProject_Add() 命令有所不同,ExternalProject_Add() 通常在构建阶段执行下载操作。FetchContent 的优势在于,一旦外部项目被下载,它就可以立即被集成到主项目的构建系统中,就像一个本地子目录一样,从而实现更流畅的工作流。

FetchContent 的核心机制:

(1)声明外部内容 (FetchContent_Declare):

FetchContent_Declare(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_TAG release-1.8.0
)

FetchContent_Declare 用于告诉CMake想要获取一个名为 googletest 的外部项目。可以指定多种来源,例如Git仓库(GIT_REPOSITORYGIT_TAG/GIT_BRANCH/GIT_COMMIT)、Subversion、Mercurial,甚至直接的HTTP(S)文件下载(URL)。这使得项目可以灵活地从各种远程源获取依赖。有关可用选项的详细内容可参考 ExternalProject_Add 命令的文档,因为 FetchContent 在底层使用了 ExternalProject 的下载机制。

(2)检查与填充 (FetchContent_GetPropertiesFetchContent_Populate):

FetchContent_GetProperties(googletest)
if(NOT googletest_POPULATED)FetchContent_Populate(googletest)# ...
endif()

FetchContent_GetProperties(googletest) 会查询 googletest 这个外部项目是否已经被下载和“填充”(populated)。它会设置一个变量,例如 googletest_POPULATED
if(NOT googletest_POPULATED) 这个条件判断至关重要,它确保 FetchContent_Populate() 只在外部项目尚未下载时才执行。如果多次调用 FetchContent_Populate() 而不进行此检查,CMake 将会报错。
FetchContent_Populate(googletest) 被调用时,CMake 会执行实际的下载操作,并将内容解压到构建目录下的一个临时位置。同时,它会定义两个重要的变量:

  • ${googletest_SOURCE_DIR}: 指向下载的Google Test源代码的路径。
  • ${googletest_BINARY_DIR}: 指向Google Test的构建目录(CMake会在这里生成构建文件)。

(3)集成子项目 (add_subdirectory):

add_subdirectory(${googletest_SOURCE_DIR}${googletest_BINARY_DIR}
)

这是将下载的外部项目集成到主项目中的关键步骤。由于Google Test本身也是一个CMake项目,它包含自己的 CMakeLists.txt 文件。add_subdirectory() 命令会处理Google Test的 CMakeLists.txt,使其内部定义的目标(如 gtestgtest_maingmockgmock_main 等)在主项目中变得可用。这意味着您现在可以直接在主项目的 CMakeLists.txt 中引用这些目标。

(4)链接测试目标 (target_link_libraries):

target_link_libraries(cpp_testPRIVATEsum_integersgtest_main
)

示例创建了一个名为 cpp_test 的测试可执行文件。这个可执行文件需要链接到自己的 sum_integers 库(因为它要测试这个库的功能),同时还需要链接到Google Test提供的 gtest_main 库。gtest_main 库包含了Google Test框架的 main 函数,负责初始化测试环境并运行所有测试。通过这种方式,避免了手动编写 main 函数来启动测试。

FetchContent 与 ExternalProject_Add 的对比:

  • FetchContent: 主要用于在配置时获取内容。一旦内容被获取,它就可以通过 add_subdirectory 立即集成到当前构建中。这非常适合那些本身也是CMake项目的依赖,或者需要在配置时就可用的依赖。它使得构建过程更像是一个单通道(single-pass)过程。
  • ExternalProject_Add: 主要用于在构建时获取和构建外部项目。它会创建一个独立的CMake目标,该目标在主项目构建时负责下载、配置和构建外部项目。这更适合那些非常庞大、需要独立构建步骤的依赖,或者那些不需要在配置时立即访问其内部目标的依赖。

本质上,FetchContent 封装并简化了 ExternalProject_Add 的某些功能,使其更易于在配置时集成外部CMake项目。

使用 GIT_TAGGIT_COMMIT 来指定Google Test的版本是一个良好的实践。这确保了团队成员和CI/CD系统在构建时总是使用相同且经过验证的Google Test版本,从而提高了构建的确定性和可重复性。如果需要升级Google Test,只需修改 FetchContent_DeclareGIT_TAG 的值,而无需更改其他任何代码。

六、更多信息与替代方案

FetchContent 模块提供了丰富的选项和功能,以满足不同的外部内容获取需求。可以查阅CMake官方文档以获取更深入的了解:https://cmake.org/cmake/help/v3.11/module/FetchContent.html

除了 FetchContent,还有其他几种常见的Google Test集成方式:

  1. 系统安装并使用 FindGTest 模块:如果Google Test已经安装在系统上(例如通过包管理器),可以使用CMake的 find_package(GTest) 命令来查找它。这需要Google Test被安装到标准路径或通过环境变量指定。一旦找到,FindGTest 模块会设置相应的变量和导入目标供链接。
    相关文档:https://cmake.org/cmake/help/v3.5/module/FindGTest.html

  2. CMake的 GoogleTest 模块和 gtest_add_tests 函数:从CMake 3.9版本开始,CMake 提供了一个专门的 GoogleTest 模块。这个模块提供了一个方便的 gtest_add_tests 函数,它可以自动扫描源代码中定义的Google Test宏(如 TEST, TEST_F 等),并自动为它们创建 add_test 条目,从而简化了测试的注册过程。
    相关文档:https://cmake.org/cmake/help/v3.9/module/GoogleTest.html

  3. 直接将Google Test源代码添加到项目:最直接但不推荐的方式是将Google Test的源代码(或其子模块)直接添加到项目仓库中,然后使用 add_subdirectory() 命令将其作为本地子项目处理。这种方式会增加您项目仓库的大小,且不利于版本管理和共享依赖。

Google Test本身是一个功能非常丰富的测试框架,提供了除了基本断言之外的许多高级特性,例如:

  • 测试夹具 (Test Fixtures): 用于为多个测试用例设置和清理共同的测试环境。
  • 参数化测试 (Parameterized Tests): 允许使用不同的输入数据多次运行同一个测试逻辑。
  • 死亡测试 (Death Tests): 用于测试程序是否在预期的情况下终止(例如,调用 abort())。
  • 事件监听器 (Event Listeners): 允许您自定义测试运行时的行为,例如生成自定义报告。
  • 模拟对象 (Mock Objects) 与 Google Mock: Google Mock 是 Google Test 的一个配套框架,用于创建和使用模拟对象,这在测试依赖于复杂外部组件的代码时非常有用。

可以访问Google Test的官方GitHub仓库获取最新信息和更详细的文档:https://github.com/google/googletest

在这里插入图片描述

http://www.dtcms.com/a/533717.html

相关文章:

  • 展开网站建设商城网站前台模板
  • 个人建站 wordpressuml电子商务网站建设文档
  • 做软件的网站phpwordpress防采集
  • 网站正在建设中 html 模板何做好网站建设销售
  • 数据库第三次项目实战
  • 合肥外贸网站建设公司排名网站建设项目实训报告
  • 免费网站的资源可以发公众号吗做产品表情的网站
  • Sdl窗口实现web view
  • 广东建设中标网站朝阳住房和城乡建设厅网站
  • dw做简易表格网站免费英文 网站模板
  • 微网站开发流程网页制作软件山水
  • 卢氏县网站建设推广深圳找做网站
  • dede模板蓝色大气简洁企业网站模板苏州哪家公司做网站
  • 【工业树莓派CM0 Dev Board】AI视觉应用部署方案:人脸检测
  • 网站建设报价单表格网站文章更新时间
  • 摄影网站源代码wordpress底部怎么改
  • 深圳设计功能网站免费搭建wordpress
  • 海南网站制作精准数据营销方案
  • 网站技术建设维护技术论文如何推广网店
  • ros2 launch 常用python模块详细使用范例
  • Spring AOP XML配置实战:传统方式的进阶应用与对比分析(含核心关键词)
  • 映像星球官网网页版入口 - 最新影视资源高清在线观看平台
  • 如何评判一个网站建设的怎么样怎么用html做移动网站吗
  • 苏州网站建设网站开发庐江网站建设
  • 1.6 大数据方法论与实践指南-数据治理工具
  • 基于python大数据的台风灾害分析及预测系统
  • 城乡住房建设网站手机网站最小宽度
  • 华为OD算法开发指导-比赛的冠亚季军
  • 算法:矩形面积II
  • app怎么查网站备案计算机网站php设计代做