C++怎么写单元测试 C++中GTest框架入门【干货】

5次阅读

直接链接gtest::gtest_main库而非手写main,cmake中需find_package(gtest required)并target_link_libraries(your_target gtest::gtest_main),否则因缺少入口导致静默跳过测试。

C++怎么写单元测试 C++中GTest框架入门【干货】

怎么在c++项目里快速跑起第一个GTest测试

能跑起来,不报链接错误,是最大门槛。很多同学卡在 main 冲突或 gtest_main 没连上。

  • 别自己写 main() —— 直接链接 gtest_main 库,它已内置了标准入口;手写 main 且没调 RUN_ALL_TESTS() 就会静默跳过所有测试
  • CMake里用 find_package(GTest REQUIRED) 后,必须同时 target_link_libraries(your_test_target GTest::gtest_main),只链 GTest::gtest 会缺 main
  • 确保测试源文件(如 test_math.cpp)被加入构建,但不要把它们混进主可执行目标里,否则符号重复

GTest断言写法和常见误用

ASSERT_*EXPECT_* 不只是“失败是否继续”的区别,还影响作用域行为——前者失败直接 return,后者继续执行本函数内后续语句。

  • ASSERT_EQ(a, b) 在函数中间失败,后续代码不执行;EXPECT_EQ(a, b) 失败后仍会跑下面的 EXPECT_TRUE(...),适合批量检查
  • 字符串比较慎用 ASSERT_STREQ:若传入 nullptr,会直接崩溃(不是断言失败),应先用 ASSERT_NE(ptr, nullptr)
  • 浮点数必须用 ASSERT_Float_EQ 或带误差的 ASSERT_NEAR(val1, val2, abs_error),直接 == 比较 float 几乎必挂

测试夹具(Test Fixture)什么时候该用、怎么组织

当多个测试需要共用初始化/清理逻辑,且涉及非 trivial 资源(如临时文件、mock 对象、全局状态重置)时,才值得上 class XxxTest : public ::testing::Test

  • 所有 SetUp() 里的对象,在每个 TEST_F 运行前重建;TearDown() 在每个测试后调用,哪怕测试崩溃也保证执行
  • 成员变量必须声明为 protected,否则子类测试无法访问;不要在构造函数里做初始化——GTest 不保证构造顺序,且可能绕过 SetUp()
  • 避免在 SetUp() 中抛异常,GTest 不捕获它,会导致整个测试程序 abort;改用 ASSERT_*() 做前置检查

编译与运行时容易被忽略的细节

GTest 默认关闭 RTTI 和异常,但你的项目如果开了 -fno-rtti-fno-exceptions,而 GTest 库是用默认选项编译的,链接时可能符号不匹配。

立即学习C++免费学习笔记(深入)”;

  • g++ -std=c++17 -pthread 编译测试代码,-pthread 是硬性要求,漏掉会触发未定义行为甚至死锁
  • 运行时加 --gtest_filter=MySuite.MyCase 可单跑某个测试;--gtest_list_tests 查看所有注册名,注意命名中的点号 . 是分隔符,不是路径
  • CI 环境中若提示 Segmentation fault (core dumped) 且无,大概率是 gtest_main 没链接成功,或者测试二进制混用了不同 ABI 版本的 libstdc++

最麻烦的永远不是写断言,而是让测试进程干净启动、资源正确释放、错误信息指向真实位置——尤其当 SetUp() 里打开文件又忘记关,第二次测试就因 EMFILE 失败时,问题藏得最深。

text=ZqhQzanResources