2016-08-23 46 views
2

我们有几个单元测试,我们希望作为构建过程的一部分运行。CMake - 运行测试作为构建过程的一部分,并将stdout输出捕获到文件中

为了达到这个目的,我有一个助手脚本,它创建一个运行测试的自定义命令,如果成功,创建一个文件"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} 
    ) 

与此有两方面的问题。

  1. 很大增加了构建时间。每个测试都必须通过一个单独的ctest过程来执行,所有注册的测试名称都是针对正则表达式进行解析的,等等。随着单个测试的数量的增加,我们有额外的时间大大增加。
  2. ctest默认输出很多噪音。指定--quiet标志抑制--output-on-failure标志,因此您可以输出有噪声或无输出 - 无法仅获得失败。

问题

有没有一种方法可以达到我想要什么?

即:

  • 手动运行测试(即:不通过CTEST)
  • 捕获输出到文件
  • 只有在指示失败的测试退出状态事件文件输出。
  • 如果测试退出状态指示成功,触摸一个哨兵文件。

一个跨平台的方法的奖励点,但如果它必须只有Linux,那就这样吧。

+1

为什么不使用ctest和cmake的集成? – fghj

+0

@ user1034749 AFAIK ctest不会将测试作为构建的一部分运行。这是一个单独的目标'make test'。我以前使用ctest来运行每个测试('COMMAND ctest --build-config $ --tests-regex $ {TEST_NAME} --output-on-failure'),但通过ctest调用每个单元测试都会大大增加编译时间 –

+0

@ user1034749更新了我与ctest有关的问题,以及为什么我要寻找替代方法 –

回答

0

回答我自己的问题,因为我找到了适合我的解决方案。

在下面的摘录中,${ARG_NAME}是我们构建并希望运行的测试二进制文件。

有同时运行测试创建2个文件

  • ${ARG_NAME}.output其中包含测试输出
  • ${ARG_NAME}.passed这是创建一个哨兵文件,如果测试成功

custom_command由几个命令,而且我们依赖于cmake在其中一个失败时会立即停止执行的事实。

我们运行测试:

${ARG_NAME} 

所有的测试输出重定向到${ARG_NAME}.output,所以当测试通过

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 

使用测试的退出状态,在我们不污染标准输出发生故障时,我们捕获文件:

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 || cat ${OUTPUT_FILE} 

但是,只有当测试通过d ·我们要创建的定点文件,所以我们猫的文件并运行false

${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 || (cat ${OUTPUT_FILE} && false) 

如果测试通过(退出状态0),那么我们将不会运行cat output && false,所以后来接下来cmake的命令运行

${CMAKE_COMMAND} -E touch ${PASSED_FILE} 

最后,我们创建一个custom_target依赖于.passed文件

set(OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}.output) 
set(PASSED_FILE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}.passed) 

# create test.passed command which runs this test and creates a sentinel file 
# if it passes 
add_custom_command(
    OUTPUT 
     ${PASSED_FILE} 

    COMMAND 
     ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME} >> ${OUTPUT_FILE} 2>&1 
       || (cat ${OUTPUT_FILE} && false) 

    COMMAND 
     ${CMAKE_COMMAND} -E touch ${PASSED_FILE} 

    COMMENT 
     "Running ${ARG_NAME} tests" 

    DEPENDS 
     ${ARG_NAME} 

    USES_TERMINAL 
    ) 

# create test.run target which depends on test.passed 
add_custom_target(${ARG_NAME}.run 
    ALL 
    DEPENDS ${PASSED_FILE} 
    ) 
1

问题是,没有标准的方法将输出从通过add_custom_command调用的命令重定向到文件。然而CMake命令execute_process确实有这种能力。

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

在你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.inexecute_process运行测试可执行文件和错误输出重定向到一个日志文件的模板测试运行脚本:

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

如果测试失败,该脚本删除定点文件,输出错误日志。 如果测试成功,脚本将创建标识文件。

相关问题