CMake - 作为构建过程的一部分运行测试并将标准输出捕获到文件

2024-05-12

我们有几个单元测试,我们希望将其作为构建过程的一部分运行。

为了实现这一目标,我有一个帮助程序脚本,它创建一个运行测试的自定义命令,如果成功,则创建一个文件"test_name.passed".

然后我添加一个自定义目标"test_name.run"这取决于"test_name.passed".

这个想法是如果"test_name.passed"不存在或早于"test_name",将运行自定义命令。

构建将继续运行自定义命令,直到测试通过。一旦通过,后续构建将不会调用自定义命令,因此不需要时不会运行测试。

到目前为止,这一切都与描述的完全一样

这是脚本:

# create command which runs the test and creates a sentinel file if it passes
add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND $<TARGET_FILE:${TEST_NAME}>
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

# create test.run module which depends on test.passed
add_custom_target(${TEST_NAME}.run
    ALL
    DEPENDS ${TEST_NAME}.passed
    )

问题——噪音stdout

问题是我们的测试经常记录大量信息stdout,这会导致构建非常嘈杂。

我现在正在尝试捕捉stdout到文件,并且仅在发生故障时才显示测试输出。

我的第一次尝试是尝试 Bash shell 脚本语法 - capturestdout到一个文件中,当退出状态为错误时,cat 该文件。

add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND $<TARGET_FILE:${TEST_NAME}> > ${TEST_NAME}.output || cat ${TEST_NAME}.output
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

这不起作用,因为即使测试失败我也会得到哨兵"test_name.passed"创建文件,这意味着下次我尝试构建它时认​​为测试通过了。

可能不符合标准的修复

通过集成ctest,我可以通过 ctest 运行每个测试并使用命令行选项--output-on-failure

add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND ctest --build-config $<CONFIGURATION> --tests-regex ${TEST_NAME} --output-on-failure
    COMMAND ${CMAKE_COMMAND} -E touch ${TEST_NAME}.passed
    DEPENDS ${TEST_NAME}
    )

这样做的问题有两个。

  1. It vastly增加构建时间。每个测试都必须通过单独的 ctest 进程执行,所有注册的测试名称都根据正则表达式进行解析,等等。随着单独测试的数量增加,我们的额外时间会增加很多。
  2. ctest 默认输出大量噪声。指定--quiet标志抑制--output-on-failure标志,因此您可以有嘈杂的输出或没有输出 - 没有办法只得到失败。

Question

有办法实现我想要的吗?

ie:

  • 手动运行测试(即:不通过 ctest)
  • 将输出捕获到文件中
  • 仅在测试退出状态指示失败时输出该文件。
  • 如果测试退出状态指示成功,请触摸哨兵文件。

跨平台方法的优点是,但如果它只能是 Linux,那就这样吧。


问题是没有标准方法来重定向通过调用的命令的输出add_custom_command到一个文件。 CMake 命令execute_process但确实有这个能力。

因此,一个可能的解决方案是从配置的 CMake 脚本运行测试可执行文件,该脚本本身作为 CMake 自定义命令运行。以下代码概述了必要的步骤:

In your CMakeLists.txt添加测试,配置 CMake 脚本模板:

configure_file("test_runner.cmake.in" "test_runner_${TEST_NAME}.cmake" @ONLY)

然后添加自定义命令以在构建时调用脚本:

add_custom_command(
    OUTPUT  ${TEST_NAME}.passed
    COMMAND ${CMAKE_COMMAND} -P "test_runner_${TEST_NAME}.cmake" $<TARGET_FILE:${TEST_NAME}>
    DEPENDS ${TEST_NAME}
    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

测试可执行文件的实际路径通过生成器表达式作为参数传递给脚本。

模板测试运行脚本test_runner.cmake.in运行测试可执行文件execute_process并将错误输出重定向到日志文件:

set (_testExecutable "${CMAKE_ARGV3}")
execute_process(COMMAND ${_testExecutable} ERROR_FILE "@[email protected] /cdn-cgi/l/email-protection" RESULT_VARIABLE _testResult)
if (_testResult)
    file(REMOVE "@[email protected] /cdn-cgi/l/email-protection")
    file(READ "@[email protected] /cdn-cgi/l/email-protection" _contents)
    message (STATUS "${_contents}")
else()
    file(WRITE "@[email protected] /cdn-cgi/l/email-protection" "")
endif()

如果测试失败,脚本将删除哨兵文件并输出错误日志。 如果测试成功,脚本将创建哨兵文件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMake - 作为构建过程的一部分运行测试并将标准输出捕获到文件 的相关文章

随机推荐