前言
单元测试是软件开发过程中的重要部分,它帮助我们确保每个组件按预期工作。C++ 中进行单元测试的一个流行选择是 Catch2 测试框架,结合 CMake 构建系统,可以创建一个强大且灵活的测试环境。在这篇博客中,将演示使用 Catch2 集成到 CMake 的 CTest 工具中进行单元测试。
环境准备
- CMake:v3.28
- Catch 2:v3.6.0 假设目录结构如下:
MyProject/
|-- CMakeLists.txt
|-- src/
|-- main.cpp
|-- test/
|-- CMakeLists.txt
|-- test.cpp
CMake 配置
根目录
CMakeLists.txt
:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.28)
...
option(ENABLE_TESTS "Build the test" ON)
...
if (ENABLE_TESTS)
# 启用测试
enable_testing()
add_subdirectory(test)
endif ()
使用
enable_testing()
启用 CTest 测试。
test
目录下的
CMakeLists.txt
:
# test/CMakeLists.txt
include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.6.0
)
FetchContent_MakeAvailable(Catch2)
add_executable(SimZipTest test.cpp)
target_link_libraries(SimZipTest PRIVATE SimZip Catch2::Catch2WithMain)
add_test(NAME SimZipTest
COMMAND $<TARGET_FILE:SimZipTest> --success
)
这里使用了 CMake 的
FetchContent
方式集成 Catch2,并指定了 Git tag 为
v3.6.0
,然后使用
target_link_libraries()
将需要链接的库和 Catch 的库链接上。
Catch 2 有两种方式:
Catch2::Catch2
和
Catch2::Catch2WithMain
。如果不需要自定义 main 函数,则使用后者。如果需要自定义 main,则应该只链接
Catch2::Catch2
。
之后便是
add_test()
命令添加测试。
注意,这里使用了
--success
选项传递给单元测试的可执行文件,用于显示 Catch 2的输出。
编写测试代码
在
test
目录下,编写
test.cpp
代码:
// test.cpp#include"../SimZip.h"#include<catch2/catch_test_macros.hpp>#include<fstream>#include<filesystem>voidgenerateData(){
std::ofstream file("data.txt");if(file.is_open()){for(auto i =0; i <10; i++){ file <<"this is data for test.";}
file.close();}}TEST_CASE("create zip","[create_zip]"){generateData();
SimZip zip("test.zip", SimZip::OpenMode::Create);REQUIRE(zip.add("data.txt")==true);REQUIRE(zip.add("data.txt","folder/rename.txt")==true);REQUIRE(zip.add("empty.txt")==false);
zip.save();}TEST_CASE("extract zip","[extract_zip]"){
SimZip zip("test.zip", SimZip::OpenMode::Read);SECTION("Extract single file from zip"){
zip.extract("data.txt","output/");REQUIRE(fs::exists("output/data.txt"));}SECTION("Extract all files from zip"){ zip.extractall("output/");
std::vector<std::string> expected_files ={"data.txt","folder/rename.txt"};for(constauto& file: expected_files){REQUIRE(fs::exists("output/"+ file));}}}
在 Catch2 测试框架中,
TEST_CASE
是一个宏,用于定义一个测试用例。这个宏接受几个参数,其中最常见的是测试用例的名称和可选的标签。
TEST_CASE("test name","[tags]"){// 测试代码 }
- 测试用例名称:第一个参数是测试用例的名称,它是一个描述性的字符串,表明测试用例的目的或测试的行为。在 Catch2 中运行测试时,这个名称会被用来识别和过滤特定的测试。
- 标签:第二个参数是可选的,它允许你为测试用例添加标签。标签通常用方括号
[]
包围,并可以用逗号,
分隔,从而为测试用例分配多个标签。标签可以用来对测试进行分类,或者在运行测试时进行过滤。
SECTION
是一个宏,用于将一个测试案例(
TEST_CASE
)划分为多个独立的部分,每个部分都可以单独运行或独立地进行断言检查。这允许你以模块化的方式编写测试,并且可以针对相同的测试设置运行多个不同的测试场景。
运行测试
使用命令:
cmake -B build
cmake --build build
ctest --test-dir build/
然后就可以看到测试结果:
$ ctest
Test project /mnt/f/Code/CppProjects/SimZip/build
Start 1: SimZipTest
1/1 Test #1: SimZipTest ....................... Passed 0.06 sec100% tests passed, 0 tests failed out of 1
Total Test time(real)=0.10 sec
对 CTest 添加
-V
参数,可以看到详细信息
ctest --test-dir build/ -V
如果你使用的是 CLion,那么可以很方便地进行测试,选择 CTest 然后运行,即可执行测试。
测试结果:
总结
CMake 和 Catch2 的结合提供了一个简单而强大的单元测试解决方案,它可以帮助你确保代码的质量。通过遵循上述步骤,你可以轻松地在你的 C++ 项目中集成测试,并保持代码的可维护性和健壮性。
版权归原作者 L-Super 所有, 如有侵权,请联系我们删除。