GoogleTest 使用 Bazel 构建入门:从 MODULE.bazel 配置到 cc_test 测试运行完整指南
本文基于 GoogleTest 官方快速上手文档 quickstart-bazel.md 展开,讲解如何在 Bazel 工作区中通过 BCR 模块声明引入 GoogleTest、编写第一个 cc_test 测试目标并成功运行它。读完后,你将掌握:Bazel 7.0+ 的 MODULE.bazel 依赖声明方式、@googletest//:gtest 与 @googletest//:gtest_main 两个核心目标的链接关系、C++17 标准参数在 Clang/GCC 与 MSVC 下的差异写法,以及如何解读 bazel test 的输出结果。
前提条件
按照官方文档,完成本教程需要准备:
- 一个兼容的操作系统(Linux、macOS、Windows 等);
- 至少支持 C++17 的 C++ 编译器;
- Bazel 7.0 或更高版本——这是 GoogleTest 团队推荐的构建系统。
关于 GoogleTest 完整支持的平台与语言标准,可参阅仓库内的 支持平台文档。
教程中的终端命令以 Unix shell 提示符展示,但在 Windows 命令行中同样适用。
创建 Bazel 工作区
Bazel 工作区是一个用于管理待构建软件源文件的目录。每个工作区根目录下都应有一个 MODULE.bazel 文件——它可以是空的,也可以包含构建产物所需的对外部依赖的声明。
第一步,创建工作区目录:
$ mkdir my_workspace && cd my_workspace
接下来创建 MODULE.bazel 文件来声明依赖。从 Bazel 7.0 开始,推荐通过 Bazel Central Registry(BCR)引入 GoogleTest。在 Bazel 工作区根目录创建 MODULE.bazel,内容如下:
# MODULE.bazel
# 选择 BCR 上当前可用的最新版本
bazel_dep(name = "googletest", version = "1.18.0")
这里选择 1.18.0 是有仓库内部依据的:GoogleTest 自身的根 CMakeLists.txt 中定义了 set(GOOGLETEST_VERSION 1.18.0),且其 MODULE.bazel 中以 module(name = "googletest", version = "head", compatibility_level = 1) 声明了 BCR 模块身份。也就是说,BCR 上发布的 GoogleTest 模块与仓库自身的 CMake/源码版本保持一致,直接消费发布版本即可获得与仓库源码等效的构建定义。
创建测试文件与 BUILD 规则
工作区就绪后,即可在项目中开始使用 GoogleTest 代码。
在 my_workspace 目录中创建名为 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)用于测试代码行为。上述示例包含了 GoogleTest 的主头文件,并演示了两个基础断言:EXPECT_STRNE 验证两个字符串不相等,EXPECT_EQ 验证 7 * 6 与 42 相等。
接着在同目录创建 BUILD 文件:
cc_test(
name = "hello_test",
size = "small",
srcs = ["hello_test.cc"],
deps = [
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
这条 cc_test 规则声明了要构建的 C++ 测试二进制,并链接到 GoogleTest 库(@googletest//:gtest)和 GoogleTest 的 main() 函数(@googletest//:gtest_main)。
深入理解两个关键依赖目标
从 GoogleTest 仓库根目录的 BUILD.bazel 可以看到这两个目标的具体定义,这也解释了 Bazel 构建为何能做到"零源码拷贝":
:gtest(BUILD.bazel#L102-L183):这是一个cc_library,其srcs通过 glob 收集了googletest/src/*.cc、googletest/src/*.h与googlemock/src/*.cc等全部实现文件(排除各-all.cc与_main.cc以避免重复编译)。值得注意的是,该库默认同时包含 Google Test 和 Google Mock 两部分源码,因此依赖@googletest//:gtest后,你既可以使用TEST、EXPECT_*断言,也可以直接使用<gmock/gmock.h>中的 Mock 能力。它还针对平台做了精细适配,例如非 Windows 平台统一追加-pthread编译选项与链接选项,Windows 平台则启用windows_export_all_symbolsfeature。:gtest_main(BUILD.bazel#L195-L204):源码只有一个文件 googlemock/src/gmock_main.cc,并设置了alwayslink = True以保证main()函数不被链接器裁剪。
再看 gmock_main.cc#L64-L72 的实现,main() 会先打印 "Running main() from gmock_main.cc",然后调用 testing::InitGoogleMock(&argc, argv)(该函数同时负责初始化 Google Test,无需再单独调用 InitGoogleTest()),最后执行 RUN_ALL_TESTS() 并返回其结果——这正是后文 bazel test 输出中那行 Running main() from gmock_main.cc 的由来。
此外,仓库中还提供了 gtest_for_library(testonly 的 :gtest 别名,BUILD.bazel#L185-L190):如果你的被测代码是被 testonly 的库依赖,用它替换 :gtest 可以绕过 Bazel 的 testonly 依赖检查。
构建并运行测试
现在可以构建并运行测试了:
$ bazel test --cxxopt=-std=c++17 --test_output=all //:hello_test
说明:
--cxxopt=-std=c++17用于显式保证 GoogleTest 以 C++17 标准编译(而非编译器默认标准)。上面的写法适用于 Clang/GCC;若使用 MSVC,等价参数为--cxxopt=/std:c++17。更多语言标准支持情况见 支持平台文档。
完整的运行输出如下:
INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured).
INFO: Found 1 test target...
INFO: From Testing //:hello_test:
==================== Test output for //:hello_test:
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from HelloTest
[ RUN ] HelloTest.BasicAssertions
[ OK ] HelloTest.BasicAssertions (0 ms)
[----------] 1 test from HelloTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
================================================================================
Target //:hello_test up-to-date:
bazel-bin/hello_test
INFO: Elapsed time: 4.190s, Critical Path: 3.05s
INFO: 27 processes: 8 internal, 19 linux-sandbox.
INFO: Build completed successfully, 27 total actions
//:hello_test PASSED in 0.1s
INFO: Build completed successfully, 27 total actions
输出中几个关键信息的对应关系:
Running main() from gmock_main.cc:来自:gtest_main依赖的main()实现(gmock_main.cc#L66);[ RUN ]/[ OK ]/[ PASSED ] 1 test.:GoogleTest 运行器对HelloTest.BasicAssertions单个用例的执行与汇总报告;bazel-bin/hello_test:Bazel 生成的测试可执行文件路径,可直接手动运行以调试;linux-sandbox:bazel test默认在沙箱中执行测试,保证隔离性。
如果你只想查看构建/测试日志而不重新执行,可将 bazel test 替换为 bazel build;若需要列出某个包下的全部测试目标,可使用 bazel query 'kind(cc_test, //...)' 辅助排查目标名。
验证依据与延伸阅读
本文涉及的构建定义均可在当前仓库中直接查证:
- 根 BUILD.bazel:
:gtest、:gtest_main、:gtest_for_library三个核心目标的完整定义与平台适配逻辑; - MODULE.bazel:GoogleTest 自身的 BCR 模块声明及其对
abseil-cpp、platforms、re2、rules_cc的依赖声明; - WORKSPACE:面向旧式 WORKSPACE 构建体系的等价依赖加载方式(
googletest_deps()); - googlemock/src/gmock_main.cc:
gtest_main提供的main()入口实现。
接下来可以继续:
- 阅读 Primer,系统学习如何编写简单的 GoogleTest 测试(测试套件、fixture、断言宏等);
- 查看 代码示例,了解参数化测试、类型化测试、死亡测试等多种 GoogleTest 特性的用法,这些示例对应的源码位于 googletest/samples/ 目录,且已由 BUILD.bazel 中的
gtest_samples等cc_test目标集成进 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