首页
/ GoogleTest 使用 Bazel 构建入门:从 MODULE.bazel 配置到 cc_test 测试运行完整指南

GoogleTest 使用 Bazel 构建入门:从 MODULE.bazel 配置到 cc_test 测试运行完整指南

2026-09-05 16:06:41作者:柏廷章Berta

本文基于 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 * 642 相等。

接着在同目录创建 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 构建为何能做到"零源码拷贝":

  • :gtestBUILD.bazel#L102-L183):这是一个 cc_library,其 srcs 通过 glob 收集了 googletest/src/*.ccgoogletest/src/*.hgooglemock/src/*.cc 等全部实现文件(排除各 -all.cc_main.cc 以避免重复编译)。值得注意的是,该库默认同时包含 Google Test 和 Google Mock 两部分源码,因此依赖 @googletest//:gtest 后,你既可以使用 TESTEXPECT_* 断言,也可以直接使用 <gmock/gmock.h> 中的 Mock 能力。它还针对平台做了精细适配,例如非 Windows 平台统一追加 -pthread 编译选项与链接选项,Windows 平台则启用 windows_export_all_symbols feature。
  • :gtest_mainBUILD.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-sandboxbazel test 默认在沙箱中执行测试,保证隔离性。

如果你只想查看构建/测试日志而不重新执行,可将 bazel test 替换为 bazel build;若需要列出某个包下的全部测试目标,可使用 bazel query 'kind(cc_test, //...)' 辅助排查目标名。

验证依据与延伸阅读

本文涉及的构建定义均可在当前仓库中直接查证:

  • BUILD.bazel:gtest:gtest_main:gtest_for_library 三个核心目标的完整定义与平台适配逻辑;
  • MODULE.bazel:GoogleTest 自身的 BCR 模块声明及其对 abseil-cppplatformsre2rules_cc 的依赖声明;
  • WORKSPACE:面向旧式 WORKSPACE 构建体系的等价依赖加载方式(googletest_deps());
  • googlemock/src/gmock_main.ccgtest_main 提供的 main() 入口实现。

接下来可以继续:

  • 阅读 Primer,系统学习如何编写简单的 GoogleTest 测试(测试套件、fixture、断言宏等);
  • 查看 代码示例,了解参数化测试、类型化测试、死亡测试等多种 GoogleTest 特性的用法,这些示例对应的源码位于 googletest/samples/ 目录,且已由 BUILD.bazel 中的 gtest_samplescc_test 目标集成进 Bazel 构建体系,可直接运行验证。
登录后查看全文
热门项目推荐
相关项目推荐