GoogleTest CMake 快速上手:用 FetchContent 声明依赖并跑通第一个单元测试
本文以仓库文档 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.cmake:cxx_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_LIBS与gtest_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,你的构建输出中会出现gmock、gmock_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)
这段配置做了四件事,逐条对照仓库源码来看:
-
enable_testing():在 CMake 中启用测试支持,是ctest识别测试用例的前提; -
add_executable(hello_test ...):声明要构建的 C++ 测试二进制; -
target_link_libraries(hello_test GTest::gtest_main):把测试二进制链接到 GoogleTest。这里的GTest::gtest_main是一个别名目标(alias target),定义于 googletest/cmake/internal_utils.cmake 的cxx_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),gtest、gtest_main、gmock、gmock_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即可传递性地获得整个框架。 -
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.txt 中 INSTALL_GTEST 默认为 ON,执行安装时会生成 GTestConfig.cmake 等包配置文件(模板见 googletest/cmake/Config.cmake.in),导出 GTest::gtest、GTest::gtest_main、GTest::gmock、GTest::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.md 与 GoogleMock 文档。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/bin 与 build/lib(由 internal_utils.cmake 中的 RUNTIME_OUTPUT_DIRECTORY/LIBRARY_OUTPUT_DIRECTORY 控制)。更多示例解读见 Samples 文档。
下一步
- 阅读 GoogleTest Primer 学习如何编写简单的测试(测试套件、测试夹具、参数化测试等);
- 查阅 代码示例 了解 GoogleTest 各类特性的用法;
- 如果你的项目使用 Bazel 而非 CMake,可改看 Quickstart for Bazel。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00