如何使用Google Test (gtest) 为c++代码编写单元测试? (基础断言)

ASSERT_失败时终止测试函数,EXPECT_仅记录错误并继续执行;前者用于前置检查,后者用于主体逻辑验证。

gtest 的 ASSERT_* 和 EXPECT_* 有什么区别?

核心区别在失败时的行为:ASSERT_* 是“硬中断”,一旦断言失败,当前测试函数立刻返回,后续语句不执行;EXPECT_* 是“软提示”,失败只记录错误,测试函数继续运行。比如你在验证对象初始化后调用多个成员函数,用 EXPECT_EQ 能一次性看到所有失败点;但若 ptrnullptr 就不该继续解引用,这时该用 ASSERT_NE(ptr, nullptr)

常见组合习惯:

  • ASSERT_* 做前置条件检查(如指针非空、文件打开成功)
  • EXPECT_* 做主体逻辑验证(如计算结果、状态值)
  • 避免在循环体内滥用 ASSERT_*,否则可能漏掉后续迭代的错误

如何写一个最简可运行的 gtest 测试用例?

不需要宏定义或复杂配置,只要包含头文件、写 TEST 宏、链接 libgtest 即可运行。注意:gtest 不依赖 main(),它自己提供,所以你的测试文件里不要写自己的 main

#include 

TEST(MathTest, AddPositiveNumbers) { EXPECT_EQ(2 + 3, 5); EXPECT_GT(10, 7); }

int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }

编译命令示例(假设已安装 gtest):

  • g++ -std=c++11 test.cpp -lgtest -lgtest_main -pthread
  • 确保链接 -lgtest_main,它提供了默认 main;如果自己写了 main,就只链 -lgtest
  • 缺少 -pthread 可能导致 segfaul

    t 或静默失败

字符串比较出错时为什么 EXPECT_EQ 报错信息看不懂?

EXPECT_EQconst char* 默认做指针比较,不是内容比较。比如 EXPECT_EQ("hello", "hello") 实际比较两个字符串字面量的地址,结果是 false —— 这不是你想要的。

正确做法:

  • EXPECT_STREQ("hello", str.c_str()) 比较 C 风格字符串
  • EXPECT_EQ(std::string("hello"), str)EXPECT_EQ("hello"s, str)(C++14 字符串字面量)让类型推导走 std::string 的重载
  • std::string 成员直接用 EXPECT_EQ 是安全的,因为有对应重载

错误示例触发的报错类似:Expected: "abc" Which is: 0x55e2a1234000 —— 这就是在告诉你,它把字符串当指针打了地址。

测试私有成员或未导出函数怎么办?

gtest 本身不提供反射或友元注入机制。强行测私有函数会破坏封装,也增加维护成本。实际中优先考虑:

  • 通过公有接口间接验证私有逻辑(例如调用 Calculate() 后检查返回值和对象状态)
  • 把关键算法抽成独立的 staticfree 函数,放在头文件中并加 inline,测试时直接调用
  • 极少数必须测私有成员的场景,可在类定义末尾加 friend class TestClassName;,并在测试文件中定义同名测试类(注意命名空间匹配)

别为了测试而改生产代码的访问修饰符,更别用 #define private public 这种 hack —— 它会让编译器跳过访问检查,但可能破坏 ABI 或引发 ODR 违规。