跳到主要内容 C++ Google Test (gtest) 全面使用指南 | 极客日志
C++
C++ Google Test (gtest) 全面使用指南 详细介绍 C++ 单元测试框架 Google Test (gtest) 的使用。内容包括 Linux 和 Windows 环境下的安装配置方法,核心概念如测试套件与测试用例的定义,以及致命与非致命断言的区别。重点讲解了测试夹具(Fixture)的生命周期管理、参数化测试和死亡测试等进阶功能。通过字符串工具类的实战案例,演示了从编写测试代码到编译运行的完整流程,旨在帮助开发者构建可靠的测试体系并集成至 CI/CD 流程。
指针猎手 发布于 2026/3/24 更新于 2026/4/16 20K 浏览一、gtest 简介
gtest 是由 Google 开发的开源 C++ 单元测试框架,遵循 BSD 开源协议,支持 Linux、Windows、Mac 等多种操作系统,可与 CMake、Visual Studio、GCC 等主流开发工具和编译环境无缝集成。其核心优势包括:
丰富的断言机制:提供了大量针对布尔值、数值、字符串、容器等类型的断言宏,支持成功/失败断言、致命/非致命断言,满足不同场景的测试需求。
灵活的测试组织方式:通过测试套件(Test Suite)和测试用例(Test Case)的层级结构,清晰组织测试代码;支持测试过滤、参数化测试、死亡测试等高级功能。
完善的报告输出:可生成详细的测试报告,包含测试用例执行结果、失败原因、执行时间等信息,支持文本、XML 等多种输出格式,便于集成到 CI/CD 流程。
轻量级与可扩展性:核心代码简洁,依赖少,易于编译和部署;同时支持自定义断言、测试监听器等扩展机制,适配复杂项目的测试需求。
二、gtest 安装与配置
gtest 的安装配置方式主要分为源码编译安装和包管理器安装,以下分别介绍 Linux(Ubuntu)和 Windows(Visual Studio)环境下的配置方法。
2.1 Linux 环境(Ubuntu)
2.1.1 包管理器安装(推荐,适用于简单需求) Ubuntu 系统可通过 apt-get 直接安装预编译的 gtest 包,命令如下:
sudo apt-get update
sudo apt-get install libgtest-dev
注意:libgtest-dev 仅安装源码和头文件,并未自动编译生成库文件,需手动编译:
cd /usr/src/gtest
sudo mkdir build && cd build
sudo cmake .
sudo make
sudo cp libgtest.a libgtest_main.a /usr/lib
2.1.2 源码编译安装(适用于需要最新版本或自定义配置) git clone https://github.com/google/googletest.git
cd googletest
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j4
sudo make install
2.2 Windows 环境(Visual Studio 2022)
2.2.1 源码编译配置
从 GitHub 下载 gtest 源码,解压后进入源码目录。
使用 CMake-GUI 生成 Visual Studio 解决方案:
点击「Browse Source」选择 gtest 源码根目录(含 CMakeLists.txt)。
点击「Browse Build」选择构建目录(如 build-vs2022)。
点击「Configure」,选择 Visual Studio 2022 和平台(x64/x86),点击「Finish」完成配置。
点击「Generate」生成解决方案文件(.sln)。
打开生成的解决方案,编译「ALL_BUILD」项目,生成静态库(gtest.lib、gtest_main.lib)。
在自己的项目中配置:
项目属性 → C/C++ → 常规 → 附加包含目录:添加 gtest 源码的 include 目录(如 googletest/include)。
项目属性 → 链接器 → 常规 → 附加库目录:添加 gtest 编译生成的库目录(如 build-vs2022/lib/Release)。
项目属性 → 链接器 → 输入 → 附加依赖项:添加 gtest.lib 和 gtest_main.lib(Debug 模式添加 gtestd.lib、gtest_maind.lib)。
三、gtest 核心概念 在使用 gtest 前,需理解其两个核心概念:测试套件(Test Suite)和测试用例(Test Case)。
测试套件(Test Suite):一组相关的测试用例的集合,通常对应一个类或一个功能模块。在 gtest 中,通过 TEST 宏定义测试套件,宏的第一个参数为测试套件名称。
测试用例(Test Case):测试套件中的单个测试单元,对应一个具体的功能点或逻辑分支。TEST 宏的第二个参数为测试用例名称。
#include <gtest/gtest.h>
TEST (Calculator, AddTest) {
EXPECT_EQ (1 + 1 , 2 );
}
TEST (Calculator, SubtractTest) {
EXPECT_EQ (3 - 1 , 2 );
}
此外,gtest 还提供了测试夹具(Test Fixture)机制,用于处理多个测试用例的共享初始化和清理逻辑(如创建对象、打开文件、释放资源等),通过继承 testing::Test 类实现。
四、gtest 常用断言 断言是 gtest 的核心功能,用于判断测试代码的执行结果是否符合预期。gtest 将断言分为两类:
致命断言(Fatal Assertion):若断言失败,当前测试用例立即终止,后续代码不再执行。宏名以 ASSERT_开头,如 ASSERT_EQ、ASSERT_TRUE。
非致命断言(Non-Fatal Assertion):若断言失败,当前测试用例继续执行,仅记录失败信息。宏名以 EXPECT_开头,如 EXPECT_EQ、EXPECT_TRUE。
推荐优先使用非致命断言,以便在一次测试中发现多个问题。以下是常用断言分类整理:
4.1 布尔值断言 断言宏 说明 示例 ASSERT_TRUE(condition) 致命断言:condition 为真 ASSERT_TRUE(1 > 0) ASSERT_FALSE(condition) 致命断言:condition 为假 ASSERT_FALSE(1 < 0) EXPECT_TRUE(condition) 非致命断言:condition 为真 EXPECT_TRUE(isEven(2)) EXPECT_FALSE(condition) 非致命断言:condition 为假 EXPECT_FALSE(isEven(3))
4.2 数值比较断言 断言宏 说明 示例 ASSERT_EQ(a, b) 致命断言:a == b(EQ=Equal) ASSERT_EQ(2+3, 5) ASSERT_NE(a, b) 致命断言:a != b(NE=Not Equal) ASSERT_NE(5, 6) ASSERT_LT(a, b) 致命断言:a < b(LT=Less Than) ASSERT_LT(3, 5) ASSERT_LE(a, b) 致命断言:a <= b(LE=Less or Equal) ASSERT_LE(4, 5) ASSERT_GT(a, b) 致命断言:a > b(GT=Greater Than) ASSERT_GT(6, 5) ASSERT_GE(a, b) 致命断言:a >= b(GE=Greater or Equal) ASSERT_GE(5, 5)
注:EXPECT_系列对应的宏(如 EXPECT_EQ、EXPECT_NE)功能相同,仅为非致命断言。
4.3 字符串断言 断言宏 说明 示例 ASSERT_STREQ(s1, s2) 致命断言:C 风格字符串 s1 == s2(区分大小写) ASSERT_STREQ("hello", "hello") ASSERT_STRNE(s1, s2) 致命断言:C 风格字符串 s1 != s2 ASSERT_STRNE("hello", "world") ASSERT_STRCASEEQ(s1, s2) 致命断言:C 风格字符串 s1 == s2(不区分大小写) ASSERT_STRCASEEQ("Hello", "hello") EXPECT_STREQ(s1, s2) 非致命断言:C 风格字符串 s1 == s2 EXPECT_STREQ(getName(), "Alice")
4.4 异常断言 #include <gtest/gtest.h>
#include <stdexcept>
TEST (ExceptionTest, DivideByZero) {
auto divide = [](int a, int b) {
if (b == 0 ) {
throw std::invalid_argument ("divide by zero" );
}
return a / b;
};
ASSERT_THROW (divide (5 , 0 ), std::invalid_argument);
ASSERT_NO_THROW (divide (6 , 2 ));
}
五、gtest 进阶功能
5.0 测试环境与生命周期管理 gtest 提供了三级测试环境的生命周期管理机制,通过重写不同的 SetUp(初始化)和 TearDown(清理)方法,可实现不同范围的资源管控。各环境的执行时机有明确区分,核心分为全局环境、局部环境和最小环境三类:
全局环境(testing::Environment):作用于所有测试用例的整个生命周期。其中 SetUp 方法在所有测试用例执行前仅执行一次,TearDown 方法在所有测试用例执行完成后仅执行一次,适用于全局资源的初始化(如数据库连接、配置加载)和清理。
局部环境(testing::Test 的静态方法):作用于某个测试夹具对应的测试套件生命周期。通过静态方法 SetUpTestCase 实现,在该夹具的第一个测试用例执行前仅执行一次;通过静态方法 TearDownTestCase 实现,在该夹具的最后一个测试用例执行完成后仅执行一次,适用于测试套件级别的共享资源管控(如创建测试数据表、初始化共享对象)。
最小环境(testing::Test 的成员方法):作用于单个测试用例的生命周期。即之前提到的 SetUp 和 TearDown 成员方法,其中 SetUp 在每个测试用例执行前执行一次,TearDown 在每个测试用例执行后执行一次,适用于单个测试用例的资源初始化(如创建临时对象)和清理。
全局环境需通过 testing::AddGlobalTestEnvironment 方法注册才能生效;局部环境和最小环境则通过测试夹具类的重写实现,具体示例如下:
5.1 测试夹具(Test Fixture) 当多个测试用例需要共享初始化和清理逻辑时,使用测试夹具。步骤如下:
继承 testing::Test 类,在类中定义共享的成员变量和方法。
重写 SetUp() 方法(可选):每个测试用例执行前调用,用于初始化资源(如创建对象)。
重写 TearDown() 方法(可选):每个测试用例执行后调用,用于清理资源(如释放对象)。
使用 TEST_F 宏定义测试用例(F=Fixture),第一个参数为夹具类名。
示例:测试计算器类的多个方法,结合全局环境、局部环境和最小环境实现资源的分级管控:
#include <gtest/gtest.h>
#include <iostream>
class GlobalEnv : public testing::Environment {
public :
void SetUp () override {
std::cout << "全局环境 SetUp:执行所有测试前的初始化(如加载全局配置)" << std::endl;
}
void TearDown () override {
std::cout << "全局环境 TearDown:执行所有测试后的清理(如释放全局资源)" << std::endl;
}
};
class Calculator {
public :
int Add (int a, int b) { return a + b; }
int Subtract (int a, int b) { return a - b; }
int Multiply (int a, int b) { return a * b; }
int Divide (int a, int b) {
if (b == 0 ) throw std::invalid_argument ("divide by zero" );
return a / b;
}
};
class CalculatorFixture : public testing::Test {
protected :
Calculator calc;
static void SetUpTestCase () {
std::cout << "局部环境 SetUpTestCase:CalculatorFixture 测试套件执行前初始化(如创建共享测试数据)" << std::endl;
}
static void TearDownTestCase () {
std::cout << "局部环境 TearDownTestCase:CalculatorFixture 测试套件执行后清理(如删除共享测试数据)" << std::endl;
}
void SetUp () override {
std::cout << "最小环境 SetUp:单个测试用例执行前初始化(如重置计算器状态)" << std::endl;
}
void TearDown () override {
std::cout << "最小环境 TearDown:单个测试用例执行后清理(如释放测试用例专属资源)" << std::endl;
}
};
TEST (GlobalEnvTest, Register) {
testing::AddGlobalTestEnvironment (new GlobalEnv);
}
TEST_F (CalculatorFixture, AddTest) {
EXPECT_EQ (calc.Add (1 , 2 ), 3 );
EXPECT_EQ (calc.Add (-1 , -2 ), -3 );
}
TEST_F (CalculatorFixture, SubtractTest) {
EXPECT_EQ (calc.Subtract (5 , 3 ), 2 );
EXPECT_EQ (calc.Subtract (3 , 5 ), -2 );
}
TEST_F (CalculatorFixture, DivideTest) {
EXPECT_EQ (calc.Divide (6 , 2 ), 3 );
ASSERT_THROW (calc.Divide (5 , 0 ), std::invalid_argument);
}
TEST (OtherTest, Test1) {
std::cout << "执行独立测试用例 Test1" << std::endl;
EXPECT_TRUE (1 == 1 );
}
TEST (OtherTest, Test3) {
std::cout << "执行独立测试用例 Test3" << std::endl;
EXPECT_FALSE (1 == 0 );
}
int main (int argc, char **argv) {
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}
程序启动后,首先执行全局环境的 SetUp(输出'全局环境 SetUp:执行所有测试前的初始化');
执行独立测试用例 Test1:先执行 Test1 的最小环境 SetUp(若有),再执行测试逻辑,最后执行 Test1 的最小环境 TearDown(若有);
执行 CalculatorFixture 测试套件:
① 先执行局部环境 SetUpTestCase(输出'局部环境 SetUpTestCase:CalculatorFixture 测试套件执行前初始化');
② 执行 AddTest:执行最小环境 SetUp → 测试逻辑 → 最小环境 TearDown;
③ 执行 SubtractTest:执行最小环境 SetUp → 测试逻辑 → 最小环境 TearDown;
④ 执行 DivideTest:执行最小环境 SetUp → 测试逻辑 → 最小环境 TearDown;
⑤ 执行局部环境 TearDownTestCase(输出'局部环境 TearDownTestCase:CalculatorFixture 测试套件执行后清理');
执行独立测试用例 Test3:先执行 Test3 的最小环境 SetUp(若有),再执行测试逻辑,最后执行 Test3 的最小环境 TearDown(若有);
所有测试用例执行完成后,执行全局环境的 TearDown(输出'全局环境 TearDown:执行所有测试后的清理')。
通过这种分级管控机制,可精准控制不同范围资源的创建和释放时机,避免资源冗余占用,同时提升测试代码的可维护性。
5.2 参数化测试 当需要对同一功能使用多组输入数据进行测试时(如测试加法的多个输入对),可使用参数化测试,避免编写重复代码。步骤如下:
定义参数类型(如输入值和预期输出的结构体)。
继承 testing::TestWithParam<参数类型> 类,创建参数化测试夹具。
使用 TEST_P 宏定义测试用例(P=Parameterized),通过 GetParam() 获取当前测试参数。
使用 INSTANTIATE_TEST_SUITE_P 宏注册测试套件,指定测试名称和参数列表。
#include <gtest/gtest.h>
struct AddParam {
int a;
int b;
int expected;
};
class AddParameterizedTest : public testing::TestWithParam<AddParam> {};
TEST_P (AddParameterizedTest, MultipleAddCases) {
AddParam param = GetParam ();
int result = param.a + param.b;
EXPECT_EQ (result, param.expected);
}
INSTANTIATE_TEST_SUITE_P (
AddTestCases,
AddParameterizedTest,
testing::Values (
AddParam{1 , 2 , 3 },
AddParam{-1 , -2 , -3 },
AddParam{0 , 0 , 0 },
AddParam{100 , 200 , 300 }
)
);
5.3 死亡测试 死亡测试用于验证程序在特定条件下是否会正常退出(如断言失败、调用 exit()),gtest 通过 ASSERT_EXIT、EXPECT_EXIT 等宏实现。
#include <gtest/gtest.h>
#include <cassert>
void CheckPositive (int x) {
assert (x > 0 );
}
TEST (DeathTest, AssertFailure) {
ASSERT_EXIT (
CheckPositive (-1 ),
testing::KilledBySignal (SIGABRT),
""
);
}
六、gtest 测试执行与报告
6.1 测试程序入口 gtest 需要在 main 函数中初始化并运行测试,可直接使用 gtest 提供的默认 main 函数(需链接 gtest_main.lib),也可自定义 main 函数:
#include <gtest/gtest.h>
int main (int argc, char **argv) {
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}
6.2 编译与运行 以 Linux 环境为例,假设有测试文件 calc_test.cpp,编译命令如下:
g++ calc_test.cpp -o calc_test -lgtest -lpthread
6.3 测试报告解读 运行测试程序后,gtest 会输出详细的测试报告,示例如下:
[==========] Running 5 tests from 2 test suites.
[----------] Global test environment set-up.
[----------] 3 tests from AddTestCases/AddParameterizedTest
[ RUN ] AddTestCases/AddParameterizedTest.MultipleAddCases /0
[ OK ] AddTestCases/AddParameterizedTest.MultipleAddCases /0 (0 ms)
[ RUN ] AddTestCases/AddParameterizedTest.MultipleAddCases /1
[ OK ] AddTestCases/AddParameterizedTest.MultipleAddCases /1 (0 ms)
[ RUN ] AddTestCases/AddParameterizedTest.MultipleAddCases /2
[ OK ] AddTestCases/AddParameterizedTest.MultipleAddCases /2 (0 ms)
[----------] 3 tests from AddTestCases/AddParameterizedTest (0 ms total)
[----------] 2 tests from CalculatorFixture
[ RUN ] CalculatorFixture.DivideTest
[ OK ] CalculatorFixture.DivideTest (0 ms)
[ RUN ] CalculatorFixture.SubtractTest
[ OK ] CalculatorFixture.SubtractTest (0 ms)
[----------] 2 tests from CalculatorFixture (0 ms total)
[----------] Global test environment tear-down
[==========] 5 tests passed.
[ PASSED ] 5 tests.
[==========]:测试开始/结束的分隔线。
[ RUN ]:正在执行的测试用例。
[ OK ]:测试用例执行成功。
[ FAILED ]:测试用例执行失败,会显示失败的断言位置和原因。
最后一行总结:总测试用例数和成功/失败数。
6.4 测试过滤 当测试用例较多时,可通过命令行参数过滤需要执行的测试用例:
./calc_test --gtest_filter=CalculatorFixture.*
./calc_test --gtest_filter=*Add*
./calc_test --gtest_filter=-CalculatorFixture.DivideTest
七、实战案例:测试一个简单的字符串工具类 以下通过实战案例,完整演示 gtest 的使用流程:测试一个简单的字符串工具类 StringUtil,包含字符串拼接、判空、转大写三个功能。
7.1 待测试代码(string_util.h) #pragma once
#include <string>
class StringUtil {
public :
static std::string Concat (const std::string& a, const std::string& b) {
return a + b;
}
static bool IsEmpty (const std::string& s) {
for (char c : s) {
if (!isspace (static_cast <unsigned char >(c))) {
return false ;
}
}
return true ;
}
static std::string ToUpper (const std::string& s) {
std::string result;
for (char c : s) {
result += toupper (static_cast <unsigned char >(c));
}
return result;
}
};
7.2 测试代码(string_util_test.cpp) #include <gtest/gtest.h>
#include "string_util.h"
TEST (StringUtil, ConcatTest) {
EXPECT_EQ (StringUtil::Concat ("hello" , "world" ), "helloworld" );
EXPECT_EQ (StringUtil::Concat ("" , "test" ), "test" );
EXPECT_EQ (StringUtil::Concat ("test" , "" ), "test" );
EXPECT_EQ (StringUtil::Concat ("a" , "b" ), "ab" );
}
TEST (StringUtil, IsEmptyTest) {
EXPECT_TRUE (StringUtil::IsEmpty ("" ));
EXPECT_TRUE (StringUtil::IsEmpty (" " ));
EXPECT_FALSE (StringUtil::IsEmpty ("hello" ));
EXPECT_FALSE (StringUtil::IsEmpty (" test " ));
}
TEST (StringUtil, ToUpperTest) {
EXPECT_EQ (StringUtil::ToUpper ("hello" ), "HELLO" );
EXPECT_EQ (StringUtil::ToUpper ("World" ), "WORLD" );
EXPECT_EQ (StringUtil::ToUpper ("123abc" ), "123ABC" );
EXPECT_EQ (StringUtil::ToUpper ("" ), "" );
EXPECT_EQ (StringUtil::ToUpper (" test " ), " TEST " );
}
int main (int argc, char **argv) {
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}
7.3 编译与运行 g++ string_util_test.cpp -o string_util_test -lgtest -lpthread -std=c++11
7.4 测试结果 [==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from StringUtil
[ RUN ] StringUtil.ConcatTest
[ OK ] StringUtil.ConcatTest (0 ms)
[ RUN ] StringUtil.IsEmptyTest
[ OK ] StringUtil.IsEmptyTest (0 ms)
[ RUN ] StringUtil.ToUpperTest
[ OK ] StringUtil.ToUpperTest (0 ms)
[----------] 3 tests from StringUtil (0 ms total)
[----------] Global test environment tear-down
[==========] 3 tests passed.
[ PASSED ] 3 tests.
所有测试用例执行成功,说明 StringUtil 类的三个功能符合预期。
八、总结与扩展 本文详细介绍了 gtest 的安装配置、核心概念、常用断言及进阶功能,并通过实战案例演示了完整的测试流程。gtest 作为一款成熟的 C++ 单元测试框架,不仅能满足基础的单元测试需求,其参数化测试、测试夹具等高级功能还能大幅提升测试效率,适配复杂项目的测试场景。
gtest 与 CI/CD 集成:将 gtest 测试结果输出为 XML 格式,集成到 Jenkins、GitLab CI 等持续集成工具。
gtest 扩展:自定义断言宏、测试监听器,实现个性化的测试需求。
gmock:Google 的 C++ 模拟框架,与 gtest 配合使用,用于测试依赖外部接口的代码。
通过熟练掌握 gtest,开发者可以构建可靠的测试体系,提前发现代码中的问题,提升软件质量和开发效率。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online