当前位置: 首页 > news >正文

C++单元测试gtest技术

本文内容主要涵盖了 Google Test 的基础概念、常用断言、测试夹具、参数化测试、异常测试、死亡测试、覆盖率分析等核心知识点,适用于 C++ 工程师岗位的面试准备。掌握这些内容有助于在实际开发中高效地编写高质量的单元测试。

#include <iostream>
#include <gtest/gtest.h>// 定义一个测试夹具类
class MyFixture : public testing::Test
{
protected:// 在所有测试用例执行前设置void SetUp() override {// 初始化代码,比如创建对象、打开文件等}// 在所有测试用例执行后清理void TearDown() override {// 清理代码,比如释放资源、关闭文件等}// 可以在这里声明一些公共的成员变量或方法,供所有测试用例使用
};// 使用 TEST_F 宏和自定义的测试夹具类来定义测试用例
TEST_F(MyFixture, MyFirstTest)
{// 第一个测试用例的代码EXPECT_TRUE(true);
}TEST_F(MyFixture, MySecondTest)
{// 第二个测试用例的代码EXPECT_EQ(1, 1);
}int main(int argc, char argv)
{::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

断言宏
(1)ASSERT_TRUE(condition): 检查条件是否为真。如果条件为假,则终止当前函数并报告失败。

(2)ASSERT_FALSE(condition): 检查条件是否为假。如果条件为真,则终止当前函数并报告失败。

(3)EXPECT_TRUE(condition): 检查条件是否为真。如果条件为假,则报告失败但继续执行后续的断言。

(4)EXPECT_FALSE(condition): 检查条件是否为假。如果条件为真,则报告失败但继续执行后续的断言。

(5)ASSERT_EQ(expected, actual): 检查预期值(expected)和实际值(actual)是否相等。如果不相等,则终止当前函数并报告失败。

(6)EXPECT_EQ(expected, actual): 检查预期值(expected)和实际值(actual)是否相等。如果不相等,则报告失败但继续执行后续的断言。

(7)ASSERT_NE(val1, val2): 检查两个值(val1 和 val2)是否不相等。如果相等,则终止当前函数并报告失败。

(8)EXPECT_NE(val1, val2): 检查两个值(val1 和 val2)是否不相等。如果相等,则报告失败但继续执行后续的断言。

以下是关于 Google Test(gtest) 的常见面试题及参考答案,适用于 C++ 工程师岗位的准备:


8.0.1. Google Test 是什么?它的主要作用是什么?

  • Google Test 是 Google 开发的一个 C++ 单元测试框架,用于编写和运行 C++ 程序的自动化测试。
  • 主要作用包括:
    • 验证函数逻辑是否正确
    • 提高代码质量与可维护性
    • 支持 TDD(测试驱动开发)
    • 支持异常处理、死亡测试等高级功能

8.0.2. 如何编写一个基本的 Google Test 测试用例?

#include <gtest/gtest.h>// 测试用例类
class MyTest : public ::testing::Test {
protected:void SetUp() override {// 初始化代码}void TearDown() override {// 清理代码}
};// 测试用例
TEST_F(MyTest, TestCaseName) {EXPECT_EQ(1 + 1, 2);ASSERT_TRUE(true);
}
  • SetUp():每个测试用例执行前调用
  • TearDown():每个测试用例执行后调用
  • TEST_F:带夹具的测试宏,适合多个测试共享初始化资源

8.0.3. Google Test 中有哪些常用的断言宏?它们的区别是什么?

断言宏类型行为
EXPECT_EQ(a, b)检查相等条件失败时输出信息并继续执行
ASSERT_EQ(a, b)检查相等条件失败时立即终止当前函数
EXPECT_TRUE(condition)检查真值条件失败时不中断执行
ASSERT_FALSE(condition)检查假值条件失败时中断执行
EXPECT_NEAR(a, b, abs_error)浮点数近似比较判断两个浮点数在误差范围内是否相等
EXPECT_THROW(statement, exception_type)异常测试检查是否抛出指定类型的异常
EXPECT_EXIT / EXPECT_DEATH死亡测试检查程序是否按预期退出或崩溃

8.0.4. TEST 和 TEST_F 的区别是什么?

特性TESTTEST_F
是否使用夹具
是否支持共享初始化/清理代码
适用场景简单独立测试多个测试共享资源

示例:

// 使用 TEST
TEST(SimpleTest, Addition) {EXPECT_EQ(1 + 1, 2);
}// 使用 TEST_F
class MathTest : public ::testing::Test {
public:int value;void SetUp() override { value = 10; }
};TEST_F(MathTest, AddTest) {EXPECT_EQ(value + 5, 15);
}

8.0.5. 如何运行所有测试用例?

./your_test_executable

也可以通过命令行参数控制运行方式:

./your_test_executable --gtest_filter=MyTest.*  # 运行特定测试套件
./your_test_executable --gtest_list_tests        # 只列出所有测试名称

8.0.6. 如何实现测试夹具(Test Fixture)?

继承 testing::Test 并重写 SetUp()TearDown() 方法:

class ListTest : public ::testing::Test {
protected:std::list<int> myList;void SetUp() override {myList.push_back(1);myList.push_back(2);}void TearDown() override {myList.clear();}
};TEST_F(ListTest, SizeIsCorrect) {EXPECT_EQ(myList.size(), 2);
}

8.0.7. 如何测试异常?

使用 EXPECT_THROWASSERT_THROW

TEST(ExceptionTest, ThrowsOnInvalidInput) {EXPECT_THROW(throw std::invalid_argument("error"), std::invalid_argument);
}

8.0.8. 如何进行死亡测试(Death Test)?

用于验证某个操作是否会引发程序崩溃或调用 exit()

TEST(DeathTest, DiesIfNull) {EXPECT_DEATH(function(nullptr), "Assertion.*failed");
}
  • EXPECT_DEATH:子进程崩溃且匹配正则表达式即通过测试
  • EXPECT_EXIT:可以检查退出码

8.0.9. 如何组织多个测试文件?

  • 每个源文件包含多个 TESTTEST_F
  • 所有测试自动注册到 Google Test 框架中
  • 在主函数中统一运行所有测试:
int main(int argc, char* argv[]) {::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

8.0.10. Google Test 如何支持参数化测试?

使用 INSTANTIATE_TEST_SUITE_P 结合 TEST_P 定义多组输入数据的测试:

class ParamTest : public ::testing::TestWithParam<int> {};TEST_P(ParamTest, IsEven) {int value = GetParam();EXPECT_EQ(value % 2, 0);
}INSTANTIATE_TEST_SUITE_P(EvenNumbers, ParamTest, testing::Values(2, 4, 6, 8));

8.0.11. 如何判断两个浮点数是否“相等”?

使用 EXPECT_FLOAT_EQEXPECT_NEAR

EXPECT_FLOAT_EQ(0.1 + 0.2, 0.3);     // 浮点精度内相等
EXPECT_NEAR(0.1 + 0.2, 0.3, 1e-6);   // 允许一定误差

8.0.12. 如何跳过某些测试?

使用 DISABLED_ 前缀:

TEST(SmokeTest, DISABLED_SlowTest) {// 被禁用的测试
}

运行时可通过过滤器启用:

./your_test_executable --gtest_also_run_disabled_tests

8.0.13. Google Test 支持哪些测试类型?

类型描述
单元测试对单个函数或类的行为进行测试
集成测试多个模块协同工作的测试
参数化测试对同一逻辑使用不同输入进行测试
死亡测试验证程序是否因非法操作而终止
性能测试可结合其他工具评估性能
异常测试检查是否抛出期望的异常

8.0.14. 如何生成测试覆盖率报告?

结合 [gcov](file://e:\rep\diary\C\StlDemo.cpp.gcov) 和 lcov 工具链:

  1. 编译时加入覆盖率选项:
    g++ -std=c++17 -lgtest -lgcov -fprofile-arcs -ftest-coverage test.cpp
    
  2. 运行测试:
    ./a.out
    
  3. 生成覆盖率报告:
    lcov --capture --directory . --output-file coverage.info
    genhtml coverage.info --output-directory out
    

8.0.15. Google Test 的优势有哪些?

优势描述
易用性语法简洁,易于集成到项目中
可扩展性强支持自定义断言、事件监听器
社区支持Google 维护,广泛使用于工业界
跨平台支持 Linux、Windows、macOS 等
支持多种测试风格包括 TDD、BDD、参数化测试等

8.0.16. 如何模拟依赖项?是否必须使用 gmock?

  • gmock 是 Google 提供的 mocking 框架,通常与 gtest 配合使用。
  • 如果只是简单打桩(Stub),可以在测试中手动实现接口模拟。

示例(不使用 gmock):

class MockDatabase {
public:virtual bool connect() { return true; }
};TEST(MockTest, ConnectSuccess) {MockDatabase db;EXPECT_TRUE(db.connect());
}

若需更复杂的模拟行为(如调用次数、参数匹配),推荐使用 gmock


8.0.17. 如何组织测试结构?

建议采用以下结构:

tests/
├── unit/
│   ├── math_test.cpp
│   └── string_utils_test.cpp
├── integration/
│   └── network_integration_test.cpp
└── parameterized/└── list_test.cpp
  • 每个 .cpp 文件对应一组相关测试
  • 使用 CMakeLists.txt 构建测试工程
  • 使用 gtest_main 库简化入口函数

8.0.18. 如何调试失败的测试?

  • 添加 --gtest_break_on_failure 参数,在断言失败时暂停:
    ./your_test_executable --gtest_break_on_failure
    
  • 使用 --gtest_catch_exceptions=0 让异常直接抛出,便于调试器捕获

8.0.19. 如何将测试结果输出为 XML 报告?

./your_test_executable --gtest_output="xml:report.xml"
  • 该 XML 格式可用于 CI 系统解析测试结果
  • Jenkins、GitLab CI 等均支持此格式

8.0.20. 如何提升单元测试的质量?

  • 覆盖关键路径:确保边界条件、错误分支都被覆盖
  • 隔离依赖:使用 mock/fake 替代数据库、网络等外部系统
  • 保持原子性:每个测试只验证一个行为
  • 命名清晰:测试名应描述被测行为
  • 避免副作用:测试之间不应相互影响

http://www.xdnf.cn/news/1108909.html

相关文章:

  • RHCSA(2)
  • 云端docker小知识
  • sqli-labs靶场通关笔记:第7-8关 布尔盲注
  • 一文理解锂电池充电、过放修复与电量测量:从原理到实战
  • Ubuntu安装Jenkins
  • 具身智能最有前景的方向之一“在线强化学习”新突破
  • arcgis投影后数据显示问题记录
  • 贪心算法题解——跳跃游戏 II【LeetCode】
  • 死锁的避免
  • LangChain 内存(Memory)
  • 创建uniapp项目引入uni-id用户体系使用beforeRegister钩子创建默认昵称
  • 9. JVM垃圾回收
  • 12. JVM的垃圾回收器
  • Agent 设计模式
  • 前后端分离项目的完整部署(Jenkins自动化部署)
  • 【从零开始编写数据库:基于Python语言实现数据库ToyDB的ACID特性】
  • 27.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--币种服务(一)
  • Android下一个简单的定时器,每隔一秒输出一个数字
  • Syntax Error: TypeError: Cannot set properties of undefined (setting ‘parent‘)
  • vue3 canvas 选择器 Canvas 增加页面性能
  • Kimi K2万亿参数开源模型原理介绍
  • 【论文阅读】HCCF:Hypergraph Contrastive Collaborative Filtering
  • 缓存三剑客解决方案
  • 【C语言】回调函数、转移表、qsort 使用与基于qsort改造冒泡排序
  • 利用docker部署前后端分离项目
  • 敏捷开发方法全景解析
  • SQL server之版本的初认知
  • C#枚举:从基础到高级的全方位解析
  • 《通信原理》学习笔记——第一章
  • 《Spring 中上下文传递的那些事儿》Part 11:上下文传递最佳实践总结与架构演进方向