首页
/ GoogleTest CMake 快速上手:用 FetchContent 声明依赖并跑通第一个单元测试

GoogleTest CMake 快速上手:用 FetchContent 声明依赖并跑通第一个单元测试

2026-09-05 22:27:58作者:尤辰城Agatha

本文以仓库文档 Quickstart: Building with CMake 为主体,带你用 CMake + FetchContent 的方式在 C++ 项目中集成 GoogleTest:从环境准备、依赖声明、编写第一个测试用例,到构建并用 ctest 运行。读完本文,你不仅能完整复现该教程,还能结合本仓库的 CMake 源码弄清楚每个配置项背后发生了什么——比如为什么要求 C++17、GTest::gtest_main 这类带命名空间的目标从何而来、gtest_discover_tests 又是如何把 TEST 宏注册成 ctest 用例的。

前置条件

按照 快速上手文档 的要求,完成本教程需要:

  • 一个兼容的操作系统(Linux、macOS、Windows 均可);
  • 一个至少支持 C++17 的 C++ 编译器;
  • CMake 以及一个配套构建工具(如 Make、Ninja,参见 CMake 官方的 Generators 文档)。

关于平台兼容性的完整说明见 Supported Platforms。文档中的终端命令以 Unix shell 提示符展示,但同样适用于 Windows 命令行。

关于 C++17 的源码级印证:当前仓库的 README 明确说明 1.18.x 分支要求至少 C++17,而仓库根目录的 CMakeLists.txt 中版本号为 GOOGLETEST_VERSION 1.18.0。更直接的证据在 googletest/cmake/internal_utils.cmakecxx_library_with_type 函数对每个 gtest/gmock 目标都执行了

target_compile_features(${name} PUBLIC cxx_std_17)

PUBLIC 意味着 C++17 要求会沿依赖关系传播到你的测试可执行文件,即使你的 CMakeLists.txt 没有显式设置标准,链接 gtest 后编译系统也会按 C++17 处理。

搭建项目并声明 GoogleTest 依赖

CMake 通过 CMakeLists.txt 配置项目的构建系统。首先创建项目目录:

$ mkdir my_project && cd my_project

在 CMake 生态中有多种表达依赖关系的方式,本教程采用 FetchContent 模块(需要 CMake ≥ 3.14,这也是教程中 cmake_minimum_required(VERSION 3.14) 的由来)。在 my_project 目录下创建 CMakeLists.txt,内容如下:

cmake_minimum_required(VERSION 3.14)
project(my_project)

# GoogleTest requires at least C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
FetchContent_Declare(
  googletest
  URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

要点解析:

  • FetchContent_Declare 声明的 GoogleTest 依赖会从 GitHub 下载一个 zip 归档。其中 03597a01ee50ed33e9dfd640b249b4be3799d395 是所使用的 GoogleTest 版本的 Git 提交哈希,官方文档建议经常更新该哈希以指向最新版本;

  • gtest_force_shared_crt 是 Windows 平台专用设置,用于防止 GoogleTest 覆盖父工程的编译器/链接器运行时配置。对照仓库源码,该选项在 googletest/CMakeLists.txt 中定义:

    option(
      gtest_force_shared_crt
      "Use shared (DLL) run-time lib even when Google Test is built as static lib."
      OFF)
    

    注意这里用的是 CACHE BOOL "" FORCE 而非普通变量赋值——目的是确保该值在任意构建目录下都强制生效。在 MSVC 场景下,googletest/cmake/internal_utils.cmake 会根据 BUILD_SHARED_LIBSgtest_force_shared_crt 的组合决定是否把 CMAKE_MSVC_RUNTIME_LIBRARY 改为静态 CRT,这正是文档中"防止覆盖父工程设置"这一注释背后的实现机制。

FetchContent_MakeAvailable 之后发生了什么

调用 FetchContent_MakeAvailable(googletest) 后,CMake 实际上会对下载好的 GoogleTest 分发目录执行 add_subdirectory。由此进入仓库根目录的 CMakeLists.txt,其中值得注意的默认配置有:

  • BUILD_GMOCK 默认为 ON(见 CMakeLists.txt),因此分发版会同时构建 Google Mock,你的构建输出中会出现 gmockgmock_main 等目标——这正是教程构建日志末尾出现 [100%] Built target gmock_main 的原因;
  • INSTALL_GTEST 默认为 ON,用于控制是否安装 GTest 的 CMake 包配置(后文"替代方案"一节会用到);
  • GTEST_HAS_ABSL 默认为 OFF,即默认不依赖 Abseil/RE2。

也就是说,一个 FetchContent_MakeAvailable 调用实际拉起了整个 googletest + googlemock 两个子项目的构建(见 googlemock/CMakeLists.txt 中对 gtest 目录的嵌套 add_subdirectory)。

编写第一个测试用例

依赖声明就绪后,即可在自己的项目里使用 GoogleTest。在 my_project 目录创建 hello_test.cc

#include <gtest/gtest.h>

// Demonstrate some basic assertions.
TEST(HelloTest, BasicAssertions) {
  // Expect two strings not to be equal.
  EXPECT_STRNE("hello", "world");
  // Expect equality.
  EXPECT_EQ(7 * 6, 42);
}

GoogleTest 提供丰富的断言宏来测试代码行为,完整列表见 Assertions Reference。上面的示例包含 GoogleTest 的主头文件 gtest/gtest.h,并演示了两个最基础的断言:EXPECT_STRNE(期望两个 C 字符串不相等)和 EXPECT_EQ(期望两值相等)。

EXPECT_* 产生非致命失败(nonfatal failure),断言失败不会中止当前测试函数,允许一次测试中报告多个失败点;ASSERT_* 则产生致命失败并立即结束当前函数。通常优先使用 EXPECT_*(详见 GoogleTest Primer)。

配置构建:启用测试、链接与自动发现

CMakeLists.txt 末尾追加以下内容:

enable_testing()

add_executable(
  hello_test
  hello_test.cc
)
target_link_libraries(
  hello_test
  GTest::gtest_main
)

include(GoogleTest)
gtest_discover_tests(hello_test)

这段配置做了四件事,逐条对照仓库源码来看:

  1. enable_testing():在 CMake 中启用测试支持,是 ctest 识别测试用例的前提;

  2. add_executable(hello_test ...):声明要构建的 C++ 测试二进制;

  3. target_link_libraries(hello_test GTest::gtest_main):把测试二进制链接到 GoogleTest。这里的 GTest::gtest_main 是一个别名目标(alias target),定义于 googletest/cmake/internal_utils.cmakecxx_library_with_type 中:

    add_library(${name} ${type} ${ARGN})
    add_library(${cmake_package_name}::${name} ALIAS ${name})
    

    配合 set(cmake_package_name GTest CACHE INTERNAL "")(见 googletest/CMakeLists.txt),gtestgtest_maingmockgmock_main 四个目标都会获得 GTest:: 前缀的别名,推荐使用别名目标以保证前向兼容。

    选择 gtest_main 而非 gtest 的原因是:前者由 googletest/src/gtest_main.cc 提供了程序入口:

    GTEST_API_ int main(int argc, char **argv) {
      printf("Running main() from %s\n", __FILE__);
      testing::InitGoogleTest(&argc, argv);
      return RUN_ALL_TESTS();
    }
    

    它替你调用 InitGoogleTest 解析命令行参数并执行 RUN_ALL_TESTS()。如果你需要自己的 main(例如做额外初始化),则应链接 GTest::gtest 并自行编写入口。在 googletest/CMakeLists.txt 中可以看到 gtest_main 以 PUBLIC 方式依赖 gtest,因此链接 GTest::gtest_main 即可传递性地获得整个框架。

  4. include(GoogleTest) + gtest_discover_tests(hello_test):启用 CMake 的 GoogleTest 模块,让 CMake 的测试运行器自动发现二进制中的测试。从教程给出的 ctest 输出可以看到其效果:1/1 Test #1: HelloTest.BasicAssertions——TEST(HelloTest, BasicAssertions) 宏定义的每个测试都被单独注册为一个 ctest 测试用例,从而可以精确到"测试套件.测试名"粒度地过滤、重跑。

构建并运行测试

现在执行三条命令完成构建与测试:

my_project$ cmake -S . -B build
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
...
-- Build files have been written to: .../my_project/build

my_project$ cmake --build build
Scanning dependencies of target gtest
...
[100%] Built target gmock_main

my_project$ cd build && ctest
Test project .../my_project/build
    Start 1: HelloTest.BasicAssertions
1/1 Test #1: HelloTest.BasicAssertions ........   Passed    0.00 sec

100% tests passed, 0 tests failed out of 1

Total Test time (real) =   0.01 sec

分步说明:

  • cmake -S . -B build:以源码目录 . 配置,产物输出到 build 目录(源目录与构建目录分离,即 out-of-source build);
  • cmake --build build:执行构建,会先编译 GoogleTest 自身的 gtest/gmock 等目标,再编译你的 hello_test
  • ctest:在构建目录下运行被发现的测试,输出显示 HelloTest.BasicAssertions 通过,1/1 全部成功。

至此,你已经成功用 GoogleTest 构建并运行了一个测试二进制。

延伸:依赖声明的其他姿势与常用构建选项

通过 find_package 使用已安装的 GoogleTest

教程默认演示 FetchContent(源码级集成),但仓库同样支持"安装后作为独立包发现"的路线:分发版的 CMakeLists.txtINSTALL_GTEST 默认为 ON,执行安装时会生成 GTestConfig.cmake 等包配置文件(模板见 googletest/cmake/Config.cmake.in),导出 GTest::gtestGTest::gtest_mainGTest::gmockGTest::gmock_main 等命名空间目标,并附带 pkgconfig 文件(见 docs/pkgconfig.md 相关说明)。此时下游项目只需:

find_package(GTest REQUIRED)
target_link_libraries(hello_test GTest::gtest_main)

两条路线的选择:需要锁定/跟踪特定提交、或希望 CMake 自动拉取依赖时用 FetchContent;依赖由系统包管理器或 CI 镜像预装时用 find_package

版本与 CMake 兼容性注意点

  • 教程要求用户项目 cmake_minimum_required(VERSION 3.14)FetchContent_MakeAvailable 的最低版本),而 GoogleTest 仓库根 CMakeLists.txt 自身要求 CMake ≥ 3.16,因此实际使用的 CMake 版本建议不低于 3.16;
  • 仓库根文件开头注明"CMake support is community-based"(CMake 支持由社区维护),如遇构建问题可参考 googletest/README.md 与官方文档。

与 Google Mock 的配合

由于 BUILD_GMOCK 默认开启,FetchContent_MakeAvailable(googletest) 之后 GTest::gmock_main 直接可用——把链接目标换成它即可编写基于 Mock 的测试,用法见 docs/reference/mocking.mdGoogleMock 文档。gmock 目标的构建定义见 googlemock/CMakeLists.txt

构建 GoogleTest 自身的示例与测试

如果想深入阅读更多用例,仓库提供了丰富的样例工程(默认不构建),可将 googletest/CMakeLists.txt 中的选项打开:

选项 默认值 作用
gtest_build_samples OFF 构建 googletest/samples 下的官方示例程序
gtest_build_tests OFF 构建 GoogleTest 自身的单元测试(约 30 个 C++ 测试 + 一批 Python 驱动的输出校验测试)
gmock_build_tests OFF 构建 Google Mock 自身的测试(定义于 googlemock/CMakeLists.txt
gtest_force_shared_crt OFF 静态链接 gtest 时也使用共享运行时库(Windows 重点)
BUILD_SHARED_LIBS OFF 构建共享库(DLL)而非静态库

例如以 Ninja 生成器并开启示例构建:

cmake -S . -B build -G Ninja -Dgtest_build_samples=ON
cmake --build build

构建产物统一输出到 build/binbuild/lib(由 internal_utils.cmake 中的 RUNTIME_OUTPUT_DIRECTORY/LIBRARY_OUTPUT_DIRECTORY 控制)。更多示例解读见 Samples 文档

下一步

  • 阅读 GoogleTest Primer 学习如何编写简单的测试(测试套件、测试夹具、参数化测试等);
  • 查阅 代码示例 了解 GoogleTest 各类特性的用法;
  • 如果你的项目使用 Bazel 而非 CMake,可改看 Quickstart for Bazel
登录后查看全文
热门项目推荐
相关项目推荐