google test 中 expect_throw 和 assert_throw 必须包裹可执行语句(如带参数的函数调用),不能仅传函数名;expect_no_throw 用于验证正常路径不抛异常;异常消息需用 try-catch 显式捕获后断言。

Google Test 能直接验证异常是否按预期抛出,但EXPECT_THROW和ASSERT_THROW必须包裹**可执行语句**,不能只写函数名或表达式;否则编译失败或测试逻辑失效。
EXPECT_THROW 和 ASSERT_THROW 的正确用法
这两个宏不是“检查函数声明”,而是“执行一段代码并捕获其抛出的异常”。常见错误是写成 EXPECT_THROW(Calculator::Divide, std::runtime_error) —— 这里传入的是函数指针,不触发调用,自然不会抛异常。
- 必须带括号和参数,例如
EXPECT_THROW(Calculator::Divide(10, 0), std::runtime_error) -
ASSERT_THROW在异常未抛出时会终止当前测试,适合关键路径;EXPECT_THROW允许后续断言继续执行 - 若被测函数需多步准备(如构造对象、修改状态),应放在宏的 statement 参数中,用花括号包裹:
EXPECT_THROW({ auto c = Calculator(); c.SetMode(UNSAFE); c.Divide(5, 0); }, std::runtime_error)
验证异常消息内容的可靠写法
仅检查异常类型不够,生产代码常依赖what()提供上下文。Google Test 本身不直接支持匹配消息字符串,需手动捕获后断言。
- 错误写法:
EXPECT_THROW(...).what()—— 宏返回 void,无法链式调用 - 正确做法:用 try-catch 显式捕获,再用
EXPECT_STREQ或EXPECT_THAT(需 gtest 1.10+ + gmock)比对:EXPECT_THROW({ try { risky_func(); } catch (const std::invalid_argument& e) { EXPECT_STREQ("index out of bounds", e.what()); throw; } }, std::invalid_argument) - 注意:末尾
throw是必须的,否则EXPECT_THROW捕获不到异常,测试失败
测试“不该抛异常”的场景
健壮性不仅看“抛得对”,还要看“不该抛时不抛”。EXPECT_NO_THROW 和 ASSERT_NO_THROW 就是为此设计,但容易被忽略其适用边界。
- 典型用途:验证正常输入下接口不崩溃,例如
EXPECT_NO_THROW(parser.Parse("valid.json")) - 它不关心返回值,只关注是否静默完成;若函数本应返回错误码而非抛异常,这里反而可能掩盖设计问题
- 与
EXPECT_THROW对称使用:同一函数,一组测“坏输入抛异常”,一组测“好输入不抛”,才算覆盖完整 - 注意:若被测代码内部有未捕获的
std::terminate(如 noexcept 函数抛异常),EXPECT_NO_THROW仍会 crash,此时需配合死亡测试ASSERT_DEATH
异常测试真正难的不是写断言,而是构造精准的触发条件——比如一个 std::out_of_range 可能来自 vector::at、string::substr 或自定义容器,堆栈信息和消息格式稍有差异,就可能导致测试在不同 STL 实现上行为不一致。动手前先确认你的异常路径是否稳定、可复现,比套用宏更重要。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











