推荐用CMake+FetchContent接入Google Test:include(FetchContent)、FetchContent_Declare指定v1.14.0 ZIP地址、FetchContent_MakeAvailable,再target_link_libraries链接gtest_main和gtest,并设C++17标准。

怎么在 C++ 项目里接入 Google Test(GTest)并跑起来
Google Test 不是系统级库,不能直接 #include <gtest></gtest> 就编译通过——你得先让它被编译器“看见”。常见错误是只下载了源码但没链接 libgtest.a 或没启用 -pthread,导致链接时报 undefined reference to `pthread_key_create'。
推荐做法:用 CMake 管理依赖。GTest 官方支持 FetchContent,不用手动 clone + make:
include(FetchContent) FetchContent_Declare( googletest URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip ) FetchContent_MakeAvailable(googletest) <p>add_executable(my_tests test_main.cpp my_class_test.cpp) target_link_libraries(my_tests gtest_main gtest) target_compile_options(my_tests PRIVATE -std=c++17)
- 必须链接
gtest_main(它提供了main()),否则自己写main时容易漏掉testing::InitGoogleTest -
-pthread会自动由gtesttarget 注入,但如果你手动写target_link_libraries漏掉gtest,就会触发 pthread 符号未定义 - GTest v1.14+ 要求 C++14 起步,
-std=c++17更稳妥,尤其用ASSERT_NO_FATAL_FAILURE等新宏时
怎么写能覆盖边界和异常路径的 TEST_F 测试用例
别只测“输入正常,输出正确”——TEST_F 的核心价值是复用 fixture 中的初始化逻辑,比如构造一个带 mock 行为的对象,再对它的不同调用组合做验证。
例如测试一个解析 JSON 字符串的类 JsonParser:
立即学习“C++免费学习笔记(深入)”;
使用 `gw` CLI 与 Google Workspace(Drive、Docs、Sheets)交互。当需要浏览、读取、创建、搜索或管理 Google Drive 中的文件时使用。
class JsonParserTest : public ::testing::Test {
protected:
void SetUp() override {
parser_ = std::make_unique<JsonParser>();
}
std::unique_ptr<JsonParser> parser_;
};
<p>TEST_F(JsonParserTest, EmptyStringReturnsNullptr) {
EXPECT<em>EQ(parser</em>->Parse(""), nullptr);
}</p><p>TEST_F(JsonParserTest, InvalidJsonThrows) {
EXPECT<em>THROW(parser</em>->Parse("{key: value}"), std::runtime_error);
}
-
SetUp()在每个TEST_F运行前执行,适合构造耗资源对象;若只需一次初始化,用static void SetUpTestSuite() -
EXPECT_THROW和ASSERT_DEATH是真断言,不是日志打印——它们会捕获异常或检查进程是否 crash,不满足则测试失败 - 别在
SetUp()里做 I/O 或网络调用,否则测试变慢、不稳定;mock 掉外部依赖才是正路
ASSERT_* 和 EXPECT_* 到底该用哪个
区别不在“强弱”,而在“是否继续执行当前测试函数”。ASSERT_EQ 失败后直接 return,后续语句不执行;EXPECT_EQ 失败只记录错误,继续跑完本测试函数所有断言。
典型误用场景:
TEST(MyTest, ProcessData) {
auto result = DoProcess(input);
ASSERT_NE(result, nullptr); // ← 必须非空,否则下面解引用崩溃
EXPECT_EQ(result->status(), OK);
EXPECT_GT(result->size(), 0);
}
- 前置条件(如指针非空、文件已打开、配置已加载)一律用
ASSERT_*,避免 segfault 或未定义行为干扰判断 - 多个并列业务逻辑校验(如字段值、状态码、长度)用
EXPECT_*,一次看到所有失败点 - 没有
ASSERT_THROW——只有EXPECT_THROW,因为 throw 是预期行为,不是前置条件
怎么验证日志、标准输出或私有函数行为
GTest 本身不拦截 stdout/stderr,也不提供反射调用私有成员的机制。强行 hack 会导致测试脆弱、维护成本高。
可行路径只有两个:
- 把日志抽象成接口(如
LoggerInterface),测试时传入MockLogger,用EXPECT_CALL(mock_logger, Log("warn")).Times(1)验证调用 - 私有函数逻辑过重?说明职责没拆开——把它抽成独立的
utils::ValidateInput()等 free function,然后直接测试这个函数 - 实在要测 std::cout?用
std::stringstream替换std::cout.rdbuf(),但仅限调试临时手段,不应出现在 CI 流水线中
最常被忽略的一点:GTest 的断言宏展开后本质是 C++ 语句,所以 EXPECT_EQ(a++, b) 会导致 a 被多增一次——永远不要在断言参数里做带副作用的表达式。

















