运行 仅更改或失败了 CMake/CTest 的测试?
Running only changed or failed tests with CMake/CTest?
我在一个拥有近 400 个测试可执行文件的大型代码库上工作,运行 时间在 0.001 秒到 1800 秒之间变化。当一些代码更改时,CMake 将仅智能地重建已更改的目标,很多时候花费的时间比实际测试 运行 将花费的时间短。
我知道的唯一方法是手动过滤您知道自己想要的测试 运行。我的直觉告诉我,我想重新 运行 任何没有成功 运行 存储的测试套件——要么是因为它失败了,要么是因为它被重新编译了。
这可能吗?如果是这样,如何?
ctest command 接受几个参数,这会影响 运行 的一组测试。例如。 "-R" - 按名称过滤测试,"-L" - 按标签过滤测试。也许,使用 dashboard-related 选项,您也可以选择 运行.
的测试
至于根据更改的可执行文件为这些选项生成值,您可以编写程序或脚本,检查可执行文件的修改时间and/or解析最后一个日志文件以查找失败的测试。
运行 仅更改可执行文件的另一种方法是将测试包装到附加脚本中。仅当满足某些条件时,此脚本才会 运行 可执行。
对于 Linux 包装器脚本可以按如下方式实现:
test_wrapper.sh:
# test_wrapper.sh <test_name> <executable> <params..>
# Run executable, given as second argument, with parameters, given as futher arguments.
#
# If environment variable `LAST_LOG_FILE` is set,
# checks that this file is older than the executable.
#
# If environment variable LAST_LOG_FAILED_FILE is set,
# check that testname is listed in this file.
#
# Test executable is run only if one of these checks succeed, or if none of checks is performed.
check_succeed=
check_performed=
if [ -n $LAST_LOG_FILE ]; then
check_performed=1
executable=
if [ ! ( -e "$LAST_LOG_FILE" ) ]; then
check_succeed=1 # Log file is absent
elif [ "$LAST_LOG_FILE" -ot "$executable" ]; then
check_succeed=1 # Log file is older than executable
fi
fi
if [ -n "$LAST_LOG_FAILED_FILE" ]; then
check_performed=1
testname=
if [ ! ( -e "$LAST_LOG_FAILED_FILE" ) ]; then
# No failed tests at all
elif grep ":${testname}$" "$LAST_LOG_FAILED_FILE" > /dev/null; then
check_succeed=1 # Test has been failed previously
fi
fi
if [ -n "$check_performed" -a -z "$check_succeed" ]; then
echo "Needn't to run test."
exit 0
fi
shift 1 # remove `testname` argument
eval "$*"
用于添加包装测试的 CMake 宏:
CMakeLists.txt:
# Similar to add_test(), but test is executed with our wrapper.
function(add_wrapped_test name command)
if(name STREQUAL "NAME")
# Complex add_test() command flow: NAME <name> COMMAND <command> ...
set(other_params ${ARGN})
list(REMOVE_AT other_params 0) # COMMAND keyword
# Actual `command` argument
list(GET other_params 0 real_command)
list(REMOVE_AT other_params 0)
# If `real_command` is a target, need to translate it to path to executable.
if(TARGET real_command)
# Generator expression is perfectly OK here.
set(real_command "$<TARGET_FILE:${real_command}")
endif()
# `command` is actually value of 'NAME' parameter
add_test("NAME" ${command} "COMMAND" /bin/sh <...>/test_wrapper.sh
${command} ${real_command} ${other_params}
)
else() # Simple add_test() command flow
add_test(${name} /bin/sh <...>/test_wrapper.sh
${name} ${command} ${ARGN}
)
endif()
endfunction(add_wrapped_test)
如果您只想 运行 那些自上次 运行 以来已更改或上次失败的可执行文件的测试,请使用
LAST_LOG_FILE=<build-dir>/Testing/Temporary/LastTest.log \
LAST_FAILED_LOG_FILE=<build-dir>/Testing/Temporary/LastTestsFailed.log \
ctest
所有其他测试将自动通过。
我在一个拥有近 400 个测试可执行文件的大型代码库上工作,运行 时间在 0.001 秒到 1800 秒之间变化。当一些代码更改时,CMake 将仅智能地重建已更改的目标,很多时候花费的时间比实际测试 运行 将花费的时间短。
我知道的唯一方法是手动过滤您知道自己想要的测试 运行。我的直觉告诉我,我想重新 运行 任何没有成功 运行 存储的测试套件——要么是因为它失败了,要么是因为它被重新编译了。
这可能吗?如果是这样,如何?
ctest command 接受几个参数,这会影响 运行 的一组测试。例如。 "-R" - 按名称过滤测试,"-L" - 按标签过滤测试。也许,使用 dashboard-related 选项,您也可以选择 运行.
的测试至于根据更改的可执行文件为这些选项生成值,您可以编写程序或脚本,检查可执行文件的修改时间and/or解析最后一个日志文件以查找失败的测试。
运行 仅更改可执行文件的另一种方法是将测试包装到附加脚本中。仅当满足某些条件时,此脚本才会 运行 可执行。
对于 Linux 包装器脚本可以按如下方式实现:
test_wrapper.sh:
# test_wrapper.sh <test_name> <executable> <params..>
# Run executable, given as second argument, with parameters, given as futher arguments.
#
# If environment variable `LAST_LOG_FILE` is set,
# checks that this file is older than the executable.
#
# If environment variable LAST_LOG_FAILED_FILE is set,
# check that testname is listed in this file.
#
# Test executable is run only if one of these checks succeed, or if none of checks is performed.
check_succeed=
check_performed=
if [ -n $LAST_LOG_FILE ]; then
check_performed=1
executable=
if [ ! ( -e "$LAST_LOG_FILE" ) ]; then
check_succeed=1 # Log file is absent
elif [ "$LAST_LOG_FILE" -ot "$executable" ]; then
check_succeed=1 # Log file is older than executable
fi
fi
if [ -n "$LAST_LOG_FAILED_FILE" ]; then
check_performed=1
testname=
if [ ! ( -e "$LAST_LOG_FAILED_FILE" ) ]; then
# No failed tests at all
elif grep ":${testname}$" "$LAST_LOG_FAILED_FILE" > /dev/null; then
check_succeed=1 # Test has been failed previously
fi
fi
if [ -n "$check_performed" -a -z "$check_succeed" ]; then
echo "Needn't to run test."
exit 0
fi
shift 1 # remove `testname` argument
eval "$*"
用于添加包装测试的 CMake 宏:
CMakeLists.txt:
# Similar to add_test(), but test is executed with our wrapper.
function(add_wrapped_test name command)
if(name STREQUAL "NAME")
# Complex add_test() command flow: NAME <name> COMMAND <command> ...
set(other_params ${ARGN})
list(REMOVE_AT other_params 0) # COMMAND keyword
# Actual `command` argument
list(GET other_params 0 real_command)
list(REMOVE_AT other_params 0)
# If `real_command` is a target, need to translate it to path to executable.
if(TARGET real_command)
# Generator expression is perfectly OK here.
set(real_command "$<TARGET_FILE:${real_command}")
endif()
# `command` is actually value of 'NAME' parameter
add_test("NAME" ${command} "COMMAND" /bin/sh <...>/test_wrapper.sh
${command} ${real_command} ${other_params}
)
else() # Simple add_test() command flow
add_test(${name} /bin/sh <...>/test_wrapper.sh
${name} ${command} ${ARGN}
)
endif()
endfunction(add_wrapped_test)
如果您只想 运行 那些自上次 运行 以来已更改或上次失败的可执行文件的测试,请使用
LAST_LOG_FILE=<build-dir>/Testing/Temporary/LastTest.log \
LAST_FAILED_LOG_FILE=<build-dir>/Testing/Temporary/LastTestsFailed.log \
ctest
所有其他测试将自动通过。