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

C++ gtest单元测试

1. 单元测试

单元测试是软件开发过程中的一种测试方法,用于验证程序中的最小可测单元,通常是方法、类和模块等。它的目的是确保每个单元都能正确执行其预定义的功能,并且其他功能单元之间的交互符合预期。

1.1. 单元测试介绍

1.1.1. 为什么需要单元测试

  • 早期发现问题:在软件开发的早期阶段发现潜在的问题和错误,避免后续开发过程中的不必要的麻烦。
  • 提高代码质量:有助于提高代码质量,减少bug,增强代码可维护性。
  • 提高开发效率:支持重构和修改,提高开发效率。

1.1.2. 单元测试的类型

  • 静态测试:在不执行程序的情况下对代码进行分析和检查的方法,包括代码审查、代码走查和静态分析工具的使用。
  • 动态测试:通过执行程序并观察其行为来测试软件的过程,包括白盒测试和黑盒测试。

1.1.3. 常用的C++单元测试框架

  • Google Test:由Google开发,支持多种测试模式,如测试夹具、参数化测试等,并且具有良好的跨平台特性。
  • Catch2:一个轻量级的测试框架,支持行为驱动开发(BDD)风格的测试。
  • Boost.Test:Boost库的一部分,功能强大且灵活,适合大型项目的测试。
  • CppUnit:类似于JUnit的框架,适用于C++。

1.1.4. 单元测试的实施步骤

  1. 编写测试用例:根据需求编写测试用例,模拟各种输入情况,验证函数的输出是否符合预期。
  2. 运行测试:使用测试框架提供的工具运行测试用例,观察测试结果。
  3. 分析结果:如果测试通过,说明代码在这些情况下工作正常;如果失败,则需要调试和修复。

1.1.5. 单元测试的最佳实践

  • 早期介入:在软件开发的早期阶段就开始编写测试用例。
  • 持续集成:结合持续集成工具,在每次代码提交后自动执行测试。
  • 编写清晰的测试用例:测试用例应该尽量简单明了,避免复杂的逻辑。

本文将介绍Google Test框架的基本使用方法,包括安装、配置、编写测试用例和运行测试等步骤。

1.2. 安装Google Test

vcpkg install gtest

1.3. 编写代码

我们的代码目录结构如下:

C:.
|   CMakeLists.txt
|   output.txt
|   run.ps1
|   tests_output.txt
|
+---.vscode
|       c_cpp_properties.json
|       settings.json
|
+---include
|       CMath.h
|       common.h
|
+---lib
|       bay.lib
|
+---src
|       CMath.cpp
|       main.cpp
|
\---testmain.cpp

1.3.1. CMath

我们写一个最简单的加法函数:


int CMath::add(int a, int b)
{return a + b;
}

1.3.2. src/main.cpp

这是咱们正常软件的入口函数,我们在这里调用CMath的add函数:


#include <iostream>
#include "CMath.h"int main() {CMath math;std::cout << math.add(1,2) << std::endl;return 0;
}

1.3.3. test/main.cpp

这是我们的单元测试代码,我们在这里调用CMath的add函数,并且使用Google Test提供的断言来验证结果:

#include <gtest/gtest.h>
#include "common.h"
#include "CMath.h"// 测试用例
TEST(AdditionTest, PositiveNumbers) {CMath math;EXPECT_EQ(math.add(1, 2), 3);
}TEST(AdditionTest, NegativeNumbers) {CMath math;EXPECT_EQ(math.add(-1, -2), -4); //单元测试结果会报错
}int main(int argc, char **argv) {::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

1.4. CMakeLists.txt

我们使用CMake来构建我们的项目,将生成可执行文件demo.exe和单元测试可执行文件runUnitTests.exe。
特别注意:

  1. 在生成runUnitTests.exe时,需要包含test/.cpp 和 src/.cpp ,同时排除掉src/main.cpp,否则会报错。
  2. 建议在test/main.cpp 中使用main(),这样链接时用GTest::gtest,而不要用GTest::gtest_main,否则会报错。

CMakeLists.txt如下:

# 指定CMake的最低版本要求
cmake_minimum_required(VERSION 3.10)# 设置项目名称和语言
project(demo LANGUAGES CXX)# 设置C++标准为C++17
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 强制要求使用指定的C++标准# 查找外部依赖包 fmt 和 spdlog
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)# 递归查找src目录下所有的cpp源文件,作为主程序源文件
file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")#创建主程序可执行文件
add_executable(${PROJECT_NAME} ${SOURCES})# 启用测试功能
enable_testing()# 递归查找test目录下所有的cpp文件,作为单元测试源文件
file(GLOB_RECURSE UNIT_TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test/*.cpp")
# 查找src目录下除main.cpp外的所有cpp文件,供测试用例复用
file(GLOB_RECURSE UNIT_TEST_SRC_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
list(FILTER UNIT_TEST_SRC_SOURCES EXCLUDE REGEX "src/main.cpp")
# 创建测试可执行文件 runUnitTests
add_executable(runUnitTests ${UNIT_TEST_SOURCES} ${UNIT_TEST_SRC_SOURCES})# 查找GTest库
find_package(GTest CONFIG REQUIRED)
# 链接GTest和GMock库到测试可执行文件
# 注意:这里只需链接gtest和gmock,不要链接gtest_main/gmock_main,否则main函数会冲突
target_link_libraries(runUnitTests PRIVATE GTest::gtest  GTest::gmock )# 添加CTest测试
add_test(AllTestsInMain runUnitTests)# 包含 GoogleTest 模块,自动发现并添加测试
include(GoogleTest)
gtest_discover_tests(runUnitTests)# 设置主程序包含目录
# PRIVATE表示这些包含目录仅在当前目标内部可见
# include/bay目录如不存在可去除
# 下面两处都可根据实际情况调整# 主程序包含目录
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
# 测试程序包含目录
target_include_directories(runUnitTests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")# 链接外部依赖库到主程序
# PRIVATE表示依赖不会传递给链接此目标的其他目标
# 如lib/bay.lib不存在可去除
# fmt和spdlog为必需target_link_libraries(${PROJECT_NAME} PRIVATE fmt::fmt            # 格式化库spdlog::spdlog      # 日志库
)target_link_libraries(runUnitTests PRIVATE fmt::fmt            # 格式化库spdlog::spdlog      # 日志库
)

1.5. 编译

# 生成构建目录并配置CMake工程
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE="${VCPKG_ROOTDIR}/scripts/buildsystems/vcpkg.cmake" # 编译工程,若成功则运行生成的可执行文件
cmake --build build ; 

1.6. 运行单元测试

有以下方式可以进行单元测试

1.6.1. 直接运行 runUnitTests.exe

输出结果如下:

3
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from AdditionTest
[ RUN      ] AdditionTest.PositiveNumbers
[       OK ] AdditionTest.PositiveNumbers (0 ms)
[ RUN      ] AdditionTest.NegativeNumbers
C:\Users\Admin\05.gtest\test\main.cpp(13): error: Expected equality of these values:math.add(-1, -2)Which is: -3-4[  FAILED  ] AdditionTest.NegativeNumbers (0 ms)
[----------] 2 tests from AdditionTest (0 ms total)[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (1 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] AdditionTest.NegativeNumbers1 FAILED TEST

有一条测试用例失败,是因为为我们特意在test/main.cpp中将输出结果设置错误。

1.6.2. 运行 CTest

cd build
ctest
# 也可采用 ctest -V  ,这样输出的结果会包含详细信息

输出结果如下:

Test project C:/Users/Admin/05.gtest/buildStart 1: AdditionTest.PositiveNumbers
1/3 Test #1: AdditionTest.PositiveNumbers .....   Passed    0.09 secStart 2: AdditionTest.NegativeNumbers
2/3 Test #2: AdditionTest.NegativeNumbers .....***Failed    0.01 secStart 3: AllTestsInMain
3/3 Test #3: AllTestsInMain ...................***Failed    0.01 sec33% tests passed, 2 tests failed out of 3Total Test time (real) =   0.13 secThe following tests FAILED:2 - AdditionTest.NegativeNumbers (Failed)3 - AllTestsInMain (Failed)
Errors while running CTest

1.6.3. visual studio code 中用插件进行单元测试

先安装插件

然后点击插件中的单元测试,点击相关测试用例,运行即可。

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

相关文章:

  • STM32八股【10】-----stm32启动流程
  • 如何利用好cursor
  • 【第四十六周】文献阅读:从 RAG 到记忆:大型语言模型的非参数持续学习
  • c++ overwrite
  • 华为OD机试真题——仿LISP运算(2025B卷:200分)Java/python/JavaScript/C/C++/GO最佳实现
  • Linux应用程序 栈溢出 内存踩踏 问题 排查学习
  • 第九课 影像文章插图及图表制作完全指南:从原理到应用
  • 市场需求文档撰写
  • C++11(2):
  • 《算法导论(第4版)》阅读笔记:p1178-p1212
  • 吴恩达机器学习笔记:逻辑回归3
  • Python元类(Metaclass)深度解析
  • Volatile的相关内容
  • Lombok与Jackson实现高效JSON序列化与反序列化
  • Python类与对象:面向对象编程的基础
  • Kubernetes 核心原理详解
  • Python实现基于线性回归的空气质量预测系统并达到目标指标
  • 内存管理 : 02 内存分区与分页
  • Python实例题:Python打造漏洞扫描器
  • 【AI论文】KRIS-基准测试:评估下一代智能图像编辑模型的基准
  • LangChain4j HelloWorld
  • 分词算法BPE详解和CLIP的应用
  • 测试计划与用例撰写指南
  • SAP Commerce(Hybris)开发实战(二):登陆生成token问题
  • 企业级智能体 —— 企业 AI 发展的下一个风口?
  • 【公式】批量添加MathType公式编号
  • [Linux]磁盘分区及swap交换空间
  • 第38节:PyTorch模型训练流程详解
  • Baklib知识中台构建实战
  • [DS]使用 Python 库中自带的数据集来实现上述 50 个数据分析和数据可视化程序的示例代码