【发布时间】:2016-08-23 15:28:01
【问题描述】:
我们希望在构建过程中运行几个单元测试。
为了实现这一点,我有一个帮助脚本,它创建一个运行测试的自定义命令,如果成功,则创建一个文件"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 脚本语法 - 将 stdout 捕获到文件中,当退出状态为错误时,对文件进行分类。
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}
)
这个问题有两个方面。
- 它大大增加了构建时间。每个测试都必须通过单独的 ctest 进程执行,所有注册的测试名称都根据正则表达式进行解析,等等。随着单独测试的数量增加,我们额外的时间会大大增加。
- ctest 默认会输出很多噪音。指定
--quiet标志会抑制--output-on-failure标志,因此您可以有嘈杂的输出或没有输出 - 没有办法只得到失败。
问题
有没有办法实现我想要的?
即:
- 手动运行测试(即:不通过 ctest)
- 将输出捕获到文件中
- 仅在测试退出状态指示失败时输出该文件。
- 如果测试退出状态指示成功,请触摸标记文件。
跨平台方法的加分点,但如果它必须仅适用于 Linux,那就这样吧。
【问题讨论】:
-
为什么不直接使用 ctest 以及它与 cmake 的集成?
-
@user1034749 AFAIK ctest 不会在构建过程中运行测试。这是一个单独的目标
make test。我之前确实使用 ctest 来运行每个测试 (COMMAND ctest --build-config $<CONFIGURATION> --tests-regex ${TEST_NAME} --output-on-failure),但是通过 ctest 调用每个单元测试会大大增加构建时间 -
@user1034749 用我在 ctest 方面的尝试更新了我的问题,以及我为什么要寻找替代方案
标签: unit-testing cmake