> 技术文档 > 【单元测试】 Google Test (gtest)使用指南_googletest

【单元测试】 Google Test (gtest)使用指南_googletest


Google Test (gtest)

Google Test 是 Google 开源的 C++ 测试框架,用于编写单元测试。它支持:

  • 丰富的断言(Assertions)
  • 测试套件(Test Suites)和测试用例(Test Cases)
  • 测试夹具(Test Fixtures)
  • 死亡测试(Death Tests)
  • 参数化测试(Value-Parameterized Tests)
  • 测试过滤与重复执行
一、安装指南

1. Linux 系统安装

# 安装依赖sudo apt-get install build-essential cmake libgtest-dev# 编译安装cd /usr/src/gtestsudo cmake .sudo makesudo mv lib/libgtest* /usr/lib/# 安装头文件sudo cp -r include/gtest /usr/include

2. Windows 系统安装

# 使用 vcpkgvcpkg install gtest:x64-windows# 配置 Visual Studio1. 工具 > 获取工具和功能 > 安装 \"C++ CMake 工具\"2. 项目属性 > C/C++ > 附加包含目录: 添加 vcpkg\\installed\\x64-windows\\include3. 链接器 > 附加库目录: 添加 vcpkg\\installed\\x64-windows\\lib4. 链接器 > 输入: 添加 gtest.lib; gtest_main.lib

3. macOS 系统安装

# Homebrew 安装brew install googletest# 手动配置 Xcode1. 项目设置 > Build Settings > Header Search Paths: /usr/local/include2. Library Search Paths: /usr/local/lib3. Link Binary With Libraries: 添加 libgtest.a, libgtest_main.a

4. 从源码编译

git clone https://github.com/google/googletest.gitcd googletestmkdir buildcd buildcmake .. # 生成 Makefilemake # 编译sudo make install # 安装到系统(默认 /usr/local)
二、测试框架架构

#mermaid-svg-Q3Ps8zD1Hihoulhb {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .error-icon{fill:#552222;}#mermaid-svg-Q3Ps8zD1Hihoulhb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Q3Ps8zD1Hihoulhb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .marker.cross{stroke:#333333;}#mermaid-svg-Q3Ps8zD1Hihoulhb svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .cluster-label text{fill:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .cluster-label span{color:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .label text,#mermaid-svg-Q3Ps8zD1Hihoulhb span{fill:#333;color:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .node rect,#mermaid-svg-Q3Ps8zD1Hihoulhb .node circle,#mermaid-svg-Q3Ps8zD1Hihoulhb .node ellipse,#mermaid-svg-Q3Ps8zD1Hihoulhb .node polygon,#mermaid-svg-Q3Ps8zD1Hihoulhb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .node .label{text-align:center;}#mermaid-svg-Q3Ps8zD1Hihoulhb .node.clickable{cursor:pointer;}#mermaid-svg-Q3Ps8zD1Hihoulhb .arrowheadPath{fill:#333333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-Q3Ps8zD1Hihoulhb .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-Q3Ps8zD1Hihoulhb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Q3Ps8zD1Hihoulhb .cluster text{fill:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb .cluster span{color:#333;}#mermaid-svg-Q3Ps8zD1Hihoulhb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Q3Ps8zD1Hihoulhb :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} Test Program Test Suite 1 Test Suite 2 Test Case 1 Test Case 2 Test Case 3 Test Case 4

三、高级断言系统

1. 二进制比较

ASSERT_EQ(5, 2+3); // 相等ASSERT_NE(0, 1); // 不等ASSERT_LT(3, 5); // 小于ASSERT_LE(4, 4); // 小于等于ASSERT_GT(10, 5); // 大于ASSERT_GE(7, 7); // 大于等于

2. 浮点数比较

ASSERT_FLOAT_EQ(0.1f, 0.1f); // 精确比较ASSERT_DOUBLE_EQ(0.1, 0.1);  // 双精度精确ASSERT_NEAR(3.14159, M_PI, 0.0001); // 允许误差

3. 字符串比较

ASSERT_STREQ(\"hello\", \"hello\"); // C字符串相等ASSERT_STRNE(\"A\", \"B\");  // C字符串不等ASSERT_STRCASEEQ(\"HELLO\", \"hello\"); // 忽略大小写

4. 异常检测

ASSERT_THROW( throw std::runtime_error(\"error\"), std::runtime_error);ASSERT_ANY_THROW(throw 1);ASSERT_NO_THROW(int x = 5);
四、测试夹具深入应用
class DatabaseTest : public ::testing::Test {protected: void SetUp() override { db.connect(\"test_db\"); db.createTable(\"Users\"); } void TearDown() override { db.dropTable(\"Users\"); db.disconnect(); } void insertUser(const std::string& name, int age) { db.execute(\"INSERT INTO Users VALUES (\'\" + name + \"\', \" + std::to_string(age) + \")\"); } Database db;};TEST_F(DatabaseTest, InsertRecord) { insertUser(\"Alice\", 30); ASSERT_EQ(db.rowCount(\"Users\"), 1);}TEST_F(DatabaseTest, DeleteRecord) { insertUser(\"Bob\", 25); db.execute(\"DELETE FROM Users\"); ASSERT_EQ(db.rowCount(\"Users\"), 0);}
五、参数化测试进阶
struct UserData { std::string name; int age; bool isValid;};class UserValidationTest : public ::testing::TestWithParam<UserData> {};TEST_P(UserValidationTest, CheckValidity) { const UserData& data = GetParam(); ASSERT_EQ(validateUser(data.name, data.age), data.isValid);}INSTANTIATE_TEST_SUITE_P( DefaultUsers, UserValidationTest, ::testing::Values( UserData{\"Alice\", 30, true}, UserData{\"\", 20, false}, // 空名字 UserData{\"Bob\", -5, false}, // 负年龄 UserData{\"Charlie\", 150, false} // 年龄过大 ));
六、死亡测试详解
TEST(DeathTest, InvalidPointer) { int* ptr = nullptr; ASSERT_DEATH(*ptr = 5, \"Segmentation fault\"); // 预期段错误}TEST(DeathTest, AssertFailure) { ASSERT_DEBUG_DEATH(assert(false), \"Assertion failed\"); // 调试模式}TEST(DeathTest, ExitCode) { ASSERT_EXIT(exit(1), testing::ExitedWithCode(1), \"\"); // 退出码检查}
七、CMake 高级集成
cmake_minimum_required(VERSION 3.14)project(GtestAdvancedExample)# 自动下载gtestinclude(FetchContent)FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.12.1)FetchContent_MakeAvailable(googletest)# 主程序add_executable(main_app src/main.cpp)# 测试程序add_executable(tests test/database_test.cpp test/user_test.cpp)target_link_libraries(tests PRIVATE gtest_main PRIVATE gmock_main)# 自动发现测试include(GoogleTest)gtest_discover_tests(tests EXTRA_ARGS --gtest_output=xml:${CMAKE_BINARY_DIR}/test_results.xml)# 添加覆盖率支持if(CMAKE_CXX_COMPILER_ID MATCHES \"GNU|Clang\") target_compile_options(tests PRIVATE --coverage -fprofile-arcs -ftest-coverage) target_link_libraries(tests PRIVATE --coverage)endif()
八、高级执行控制

1. 测试筛选

# 运行特定测试套件./tests --gtest_filter=DatabaseTest.*# 排除特定测试./tests --gtest_filter=-*.DeathTest# 正则表达式匹配./tests --gtest_filter=*Validation*.*Invalid*

2. 测试重复与随机化

# 重复执行100次./tests --gtest_repeat=100# 随机执行顺序./tests --gtest_shuffle --gtest_random_seed=42# 遇到失败时停止./tests --gtest_break_on_failure

3. 输出控制

# XML报告./tests --gtest_output=xml:report.xml# JSON报告./tests --gtest_output=json:report.json# 详细输出./tests --gtest_print_time=0 --gtest_color=no
九、与CI系统集成

GitLab CI 示例

stages: - testgtest: stage: test image: ubuntu:22.04 script: - apt-get update && apt-get install -y build-essential cmake git - git clone https://github.com/google/googletest.git - cd googletest && mkdir build && cd build - cmake .. && make && make install - cd ../../project - mkdir build && cd build - cmake .. && make - ./tests --gtest_output=xml:test_report.xml artifacts: paths: - build/test_report.xml reports: junit: build/test_report.xml
十、性能测试集成
TEST(PerformanceTest, VectorPushBack) { const int N = 1000000; std::vector<int> v; auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < N; ++i) { v.push_back(i); } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); std::cout << \"Time taken: \" << duration.count() << \" ms\" << std::endl; // 性能断言 ASSERT_LT(duration.count(), 50); // 应在50ms内完成}
十一、常见问题解决方案
问题现象 解决方案 链接错误:未定义引用 添加 -lgtest -lgtest_main -lpthread 链接选项 测试未执行 检查测试宏拼写,确保使用 TEST()TEST_F() 内存泄漏检测 使用 --gtest_catch_exceptions=0 禁用异常捕获 多线程测试失败 使用 testing::FLAGS_gtest_death_test_style=\"threadsafe\" Visual Studio 调试问题 在属性 > 调试 > 环境添加 PATH=$(SolutionDir)vcpkg\\installed\\x64-windows\\bin
十二、最佳实践
  1. 测试命名规范

    • 测试套件:被测试类名(如 DatabaseTest
    • 测试用例:行为描述(如 InsertValidRecord_Success
  2. 测试组织

    project/├── src/└── test/ ├── unit/ │ ├── database_test.cpp │ └── user_test.cpp ├── integration/ └── performance/
  3. 测试原则

    • 每个测试验证单一行为
    • 避免测试间依赖
    • 使用夹具减少重复代码
    • 优先使用 EXPECT_ 而非 ASSERT_ 除非后续操作无效
  4. 测试覆盖率

    # 生成覆盖率报告gcovr -r . --exclude test/ --html-details coverage.html

Google Mock (gmock) 安装与使用指南

Google Mock (gmock) 是 Google Test (gtest) 的扩展库,用于创建模拟对象(Mock Objects),简化 C++ 单元测试中的依赖隔离。

一、CMake 项目集成

CMakeLists.txt 中添加:

find_package(GTest REQUIRED)find_package(GMock REQUIRED)add_executable(MyTests test.cpp)target_link_libraries(MyTests PRIVATE GTest::gtest_main GMock::gmock)

二、核心使用步骤
1. 定义接口类
class DataBase {public: virtual ~DataBase() {} virtual bool Connect(const std::string& host) = 0; virtual int Query(const std::string& sql) = 0;};
2. 创建 Mock 类
#include class MockDataBase : public DataBase {public: MOCK_METHOD(bool, Connect, (const std::string& host), (override)); MOCK_METHOD(int, Query, (const std::string& sql), (override));};
3. 设置 Mock 行为
using ::testing::Return;using ::testing::_;TEST(DatabaseTest, BasicTest) { MockDataBase mockDB; // 设置预期行为 EXPECT_CALL(mockDB, Connect(\"localhost\")) .WillOnce(Return(true)); // 模拟返回 true EXPECT_CALL(mockDB, Query(_)) .WillOnce(Return(100)); // 匹配任意参数,返回 100 // 测试使用 Mock 对象 ASSERT_TRUE(mockDB.Connect(\"localhost\")); ASSERT_EQ(mockDB.Query(\"SELECT * FROM users\"), 100);}

三、常用匹配器(Matchers)
匹配器 作用 Eq(value) 值等于 Ge(value) 大于等于 Contains(str) 字符串包含 StartsWith(prefix) 字符串开头匹配 _ 匹配任意参数

示例:

EXPECT_CALL(mock, Query(StartsWith(\"SELECT\"))) .WillRepeatedly(Return(200));

四、高级用法
  1. 序列控制

    using ::testing::InSequence;{ InSequence seq; // 定义顺序 EXPECT_CALL(mock, Step1()); EXPECT_CALL(mock, Step2()); // Step1 必须在 Step2 前调用}
  2. 多次调用

    EXPECT_CALL(mock, Process()) .Times(3)  // 预期调用 3 次 .WillRepeatedly(Return(1));
  3. 参数保存

    std::string saved_arg;EXPECT_CALL(mock, Log(::testing::_)) .WillOnce(::testing::SaveArg<0>(&saved_arg)); // 保存第一个参数

五、常见问题解决
  1. 链接错误

    • 确保 CMake 正确找到库:find_package(GTest REQUIRED)
    • 检查链接顺序:先 gtestgmock
  2. 未调用 Mock 方法

    • 使用 ::testing::StrictMock 替代 Mock 类,严格检查所有预期调用:
      ::testing::StrictMock<MockDataBase> strictMock;
  3. 多线程问题

    • 使用 InSequenceAfter 控制调用顺序
    • 避免全局 Mock 对象

六、完整示例
#include #include // 接口class Logger {public: virtual void Write(const std::string& msg) = 0;};// Mock 类class MockLogger : public Logger {public: MOCK_METHOD(void, Write, (const std::string& msg), (override));};// 被测类class Service {public: Service(Logger* logger) : logger_(logger) {} void DoWork() { logger_->Write(\"Starting work...\"); // 业务逻辑 logger_->Write(\"Work completed\"); }private: Logger* logger_;};// 测试TEST(ServiceTest, LoggingTest) { MockLogger logger; Service service(&logger); EXPECT_CALL(logger, Write(\"Starting work...\")); EXPECT_CALL(logger, Write(\"Work completed\")); service.DoWork(); // 验证日志调用}

十三、扩展资源
  1. GoogleTest 官方文档
  2. GoogleMock 用户指南
  3. 高级测试技巧
  4. 测试驱动开发(TDD)实战