C++ gtest单元测试_c++单元测试
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.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|\\---test main.cpp
1.3.1. CMath
我们写一个最简单的加法函数:
int CMath::add(int a, int b){ return a + b;}
1.3.2. src/main.cpp
这是咱们正常软件的入口函数,我们在这里调用CMath的add函数:
#include #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 #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。
特别注意:
- 在生成runUnitTests.exe时,需要包含test/.cpp 和 src/.cpp ,同时排除掉src/main.cpp,否则会报错。
- 建议在test/main.cpp 中使用main(),这样链接时用
GTest::gtest
,而不要用GTest::gtest_main
,否则会报错。
CMakeLists.txt如下:
# 指定CMake的最低版本要求cmake_minimum_required(VERSION 3.10)# 设置项目名称和语言project(demo LANGUAGES CXX)# 设置C++标准为C++17set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON) # 强制要求使用指定的C++标准# 查找外部依赖包 fmt 和 spdlogfind_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\")# 创建测试可执行文件 runUnitTestsadd_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.NegativeNumbersC:\\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.NegativeNumbers 1 FAILED TEST
有一条测试用例失败,是因为为我们特意在test/main.cpp中将输出结果设置错误。
1.6.2. 运行 CTest
cd buildctest# 也可采用 ctest -V ,这样输出的结果会包含详细信息
输出结果如下:
Test project C:/Users/Admin/05.gtest/build Start 1: AdditionTest.PositiveNumbers1/3 Test #1: AdditionTest.PositiveNumbers ..... Passed 0.09 sec Start 2: AdditionTest.NegativeNumbers2/3 Test #2: AdditionTest.NegativeNumbers .....***Failed 0.01 sec Start 3: AllTestsInMain3/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 中用插件进行单元测试
先安装插件
然后点击插件中的单元测试,点击相关测试用例,运行即可。