步骤 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 还具有用于脚本、夹具、 Sanitizers、作业服务器、度量报告等的高级机制。有关更多信息,请参阅 ctest(1) 手册。

练习 1 - 添加测试

CTest 的约定规定,测试的构建和运行基于一个名为 BUILD_TESTING 的默认值为 ON 的变量。当使用 CTest 模块使用完整的 CTest 功能时,这个 option() 会为我们设置好。当使用更精简的测试方法时,项目预期会自行设置该选项(或至少是类似名称的选项)。

BUILD_TESTING 为 true 时,应在根 CMakeLists.txt 中调用 enable_testing() 命令。

enable_testing()

这将生成所有必要的元数据到构建树中,以便 CTest 找到并运行测试。

完成这些后,就可以使用 add_test() 命令在项目的任何地方创建测试。该命令的语义类似于 add_custom_command();我们可以将一个可执行目标命名为“命令”。

add_test(
  NAME MyAppWithTestFlag
  COMMAND MyApp --test
)

目标

为 MathFunctions 库向项目中添加测试,并使用 CTest 运行它们。

有用资源

要编辑的文件

  • Tests/CMakeLists.txt

  • CMakeLists.txt

开始

一个测试程序已在 Tests/TestMathFunctions.cxx 文件中编写。该程序接受一个命令行参数,即要测试的数学函数,有效值为 addmulsqrtsub。如果操作被识别且计算值有效,则返回码为零,否则为非零。

完成 TODO 1TODO 7

构建并运行

无需特殊配置,按常规进行配置和构建。

cmake --preset tutorial
cmake --build build

验证所有测试都已通过 CTest。

注意

如果使用多配置生成器(例如 Visual Studio),则需要使用 ctest -C <config> <remaining flags> 来指定配置,其中 <config> 是一个值,如 DebugRelease。这是在使用多配置生成器时一直需要注意的,在未来的命令中不会特别指出。

ctest --test-dir build

您可以使用 -R 标志来运行单个测试。

ctest --test-dir build -R sqrt

解决方案

首先,我们为测试添加一个新的可执行文件。

TODO 1-2:点击显示/隐藏答案
TODO 1-2:Tests/CMakeLists.txt
add_executable(TestMathFunctions)

target_sources(TestMathFunctions
  PRIVATE
    TestMathFunctions.cxx
)

然后,我们链接要测试的库。

TODO 3:点击显示/隐藏答案

我们需要为每个有效操作调用 add_test(),但这会很重复,所以我们编写一个 function() 来为我们完成这项工作。

TODO 4:点击显示/隐藏答案
TODO 4:Tests/CMakeLists.txt
function(MathFunctionTest op)
  add_test(
    NAME ${op}
    COMMAND TestMathFunctions ${op}
  )
endfunction()

现在我们可以使用我们的 function() 来添加所有测试。

TODO 5:点击显示/隐藏答案
TODO 5:Tests/CMakeLists.txt
MathFunctionTest(add)
MathFunctionTest(mul)
MathFunctionTest(sqrt)
MathFunctionTest(sub)

最后,我们可以在顶层 CMakeLists.txt 中添加 BUILD_TESTING 选项,并有条件地启用测试的构建和运行。

TODO 6-7:点击显示/隐藏答案
TODO 6:CMakeLists.txt
option(BUILD_TESTING "Enable testing and build tests" ON)
TODO 7:CMakeLists.txt
if(BUILD_TESTING)
  enable_testing()
  add_subdirectory(Tests)
endif()