第 8 步:测试与 CTest¶
从历史上看,测试并不是构建系统的职责。充其量,它可能包含一个映射到构建和运行项目测试的特定目标。
在 CMake 生态系统中,情况恰恰相反。CMake 的测试生态系统被称为 CTest。这个生态系统既简单得出奇,又极其强大。事实上,它功能强大到需要一份完整的独立教程来描述我们可以用它实现的一切。
本节不是那份教程。在这一步中,我们将初步了解 CTest 提供的一些功能。
背景¶
其核心是,CTest 是一个任务启动器,它运行命令并报告它们返回的是零值还是非零值。我们将在这个层面使用 CTest。
CMake 通过 enable_testing() 和 add_test() 命令与 CTest 直接集成。这些命令允许 CMake 在构建文件夹中设置必要的架构,以便 CTest 能够发现、运行和报告我们可能感兴趣的各种测试。
设置并构建测试后,调用 CTest 最简单的方法是在构建目录中直接运行:
ctest --test-dir build
这将运行所有可用的测试。可以使用正则表达式运行特定的测试。
ctest --test-dir build -R SpecificTest
CTest 还具有用于脚本编写、测试夹具 (fixtures)、消毒剂 (sanitizers)、作业服务器 (job servers)、指标报告等的高级机制。有关更多信息,请参阅 ctest(1) 手册。
练习 1 - 添加测试¶
CTest 的惯例规定,构建和运行测试应基于一个名为 BUILD_TESTING 的默认值为 ON 的变量。当通过 CTest 模块使用 CTest 的全部功能时,系统会为我们设置此 option()。当使用更精简的测试方法时,项目需要自行设置该选项(或至少是一个名称类似的选项)。
当 BUILD_TESTING 为真时,应在根目录的 CML(CMakeLists.txt)中调用 enable_testing() 命令。
enable_testing()
这将为构建树生成 CTest 查找和运行测试所需的所有必要元数据。
完成此操作后,可以使用 add_test() 命令在项目中的任何位置创建测试。该命令的语义类似于 add_custom_command();我们可以指定一个可执行目标作为“命令”。
add_test(
NAME MyAppWithTestFlag
COMMAND MyApp --test
)
目标¶
为 MathFunctions 库添加测试,并使用 CTest 运行它们。
有用资源¶
要编辑的文件¶
Tests/CMakeLists.txtCMakeLists.txt
开始¶
文件 Tests/TestMathFunctions.cxx 中编写了一个测试程序。该程序接受一个命令行参数,即要测试的数学函数,有效值为 add、mul、sqrt 和 sub。如果识别出操作且计算出的值有效,则返回码为零,否则为非零。
完成 TODO 1 到 TODO 7。
构建并运行¶
无需特殊配置,像往常一样配置和构建即可。
cmake --preset tutorial
cmake --build build
使用 CTest 验证所有测试是否通过。
注意
如果使用多配置生成器(例如 Visual Studio),则需要使用 ctest -C <config> <remaining flags> 指定配置,其中 <config> 是诸如 Debug 或 Release 之类的值。使用多配置生成器时始终如此,后续命令中将不再专门说明。
ctest --test-dir build
你可以使用 -R 标志运行单个测试。
ctest --test-dir build -R sqrt
解决方案¶
首先,我们为测试添加一个新的可执行文件。
TODO 1-2: 点击以显示/隐藏答案
add_executable(TestMathFunctions)
target_sources(TestMathFunctions
PRIVATE
TestMathFunctions.cxx
)
然后我们链接我们要测试的库。
TODO 3:点击显示/隐藏答案
target_link_libraries(TestMathFunctions
PRIVATE
MathFunctions
)
我们需要为每个有效操作调用 add_test(),但这会变得重复,因此我们编写一个 function() 来替我们完成。
TODO 4:点击显示/隐藏答案
function(MathFunctionTest op)
add_test(
NAME ${op}
COMMAND TestMathFunctions ${op}
)
endfunction()
现在我们可以使用我们的 function() 来添加所有测试。
TODO 5:点击显示/隐藏答案
MathFunctionTest(add)
MathFunctionTest(mul)
MathFunctionTest(sqrt)
MathFunctionTest(sub)
最后,我们可以在顶层 CML 中添加 BUILD_TESTING 选项,并有条件地启用测试的构建和运行。