Я работаю с большой кодовой базой, в которой имеется около 400 тестовых исполняемых файлов, а время выполнения варьируется от 0,001 секунды до 1800 секунд. Когда некоторые изменения кода изменяются, CMake будет разумно перестраивать только те цели, которые изменились, во много раз короче, чем фактический запуск теста.
Единственный способ, которым я знаю об этом, — это ручная фильтрация тестов, которые вы хотите запустить. Моя интуиция говорит, что я бы хотел перезапустить любой набор тестов, в котором не был сохранен успешный запуск — либо потому, что он не прошел, либо потому, что он был перекомпилирован.
Это возможно? Если так, то как?
команда ctest принимает несколько параметров, которые влияют на набор тестов для запуска. Например. , «- R» — фильтровать тесты по имени, «-L» — фильтровать тесты по метке. Возможно, используя опции, связанные с панелью мониторинга, вы также можете выбрать тесты для запуска.
Что касается генерации значений для этих опций в соответствии с измененными исполняемыми файлами, вы можете написать программу или скрипт, который проверяет время модификации исполняемых файлов и / или анализирует последний файл журнала для поиска неудачных тестов.
Другой способ запуска только измененных исполняемых файлов — это обернуть тесты в дополнительный скрипт. Этот скрипт запускает исполняемый файл, только если выполняется какое-то условие.
Для 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=$2
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=$1
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
Все остальные тесты будут автоматически пройдены.
Других решений пока нет …