Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否仅使用CMake/CTest运行已更改或失败的测试?_C++_Unit Testing_Cmake_Build Process_Ctest - Fatal编程技术网

C++ 是否仅使用CMake/CTest运行已更改或失败的测试?

C++ 是否仅使用CMake/CTest运行已更改或失败的测试?,c++,unit-testing,cmake,build-process,ctest,C++,Unit Testing,Cmake,Build Process,Ctest,我在一个大型代码库上工作,该代码库有近400个测试可执行文件,运行时间在0.001秒到1800秒之间变化。当一些代码发生更改时,CMake将仅智能地重建已更改的目标,所需时间比实际测试运行所需时间短很多倍 我知道的唯一方法是手动筛选您知道要运行的测试。我的直觉告诉我,我想重新运行任何没有成功运行的测试套件——要么是因为它失败了,要么是因为它被重新编译了 这可能吗?如果是,怎么做 接受多个参数,这些参数会影响要运行的测试集。例如,“-R”-按名称筛选测试,“-L”-按标签筛选测试。也许,使用仪表板

我在一个大型代码库上工作,该代码库有近400个测试可执行文件,运行时间在0.001秒到1800秒之间变化。当一些代码发生更改时,CMake将仅智能地重建已更改的目标,所需时间比实际测试运行所需时间短很多倍

我知道的唯一方法是手动筛选您知道要运行的测试。我的直觉告诉我,我想重新运行任何没有成功运行的测试套件——要么是因为它失败了,要么是因为它被重新编译了

这可能吗?如果是,怎么做

接受多个参数,这些参数会影响要运行的测试集。例如,“-R”-按名称筛选测试,“-L”-按标签筛选测试。也许,使用仪表板相关选项,您还可以选择要运行的测试

至于根据更改的可执行文件生成这些选项的值,您可以编写程序或脚本,检查可执行文件的修改时间和/或解析最后一个日志文件以查找失败的测试

仅运行已更改的可执行文件的另一种方法是将测试包装到其他脚本中。仅当满足某些条件时,此脚本才会运行可执行文件

For Linux包装器脚本的实现方式如下:

测试包装器.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 "$*"
# 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)
#test_wrapper.sh
#运行可执行文件,作为第二个参数,参数作为进一步的参数。
#
#如果设置了环境变量“LAST_LOG_FILE”,
#检查此文件是否早于可执行文件。
#
#如果设置了环境变量LAST_LOG_FAILED_FILE,
#检查testname是否在此文件中列出。
#
#仅当其中一项检查成功或未执行任何检查时,才会运行测试可执行文件。
检查你成功了吗=
检查是否已执行=
如果[-n$LAST_LOG_FILE];然后
执行的检查=1
可执行文件=$2
如果[!(-e“$LAST_LOG_FILE”);然后
检查_success=1#缺少日志文件
elif[“$LAST_LOG_FILE”-ot“$executable”];然后
检查_success=1#日志文件比可执行文件旧
fi
fi
如果[-n“$LAST_LOG_FAILED_FILE”];然后
执行的检查=1
testname=$1
如果[!(-e“$LAST\u LOG\u FAILED\u FILE”);然后
#根本没有失败的测试
elif grep“${testname}\$”“$LAST\u LOG\u FAILED\u FILE”>/dev/null;然后
检查_success=1#之前测试失败
fi
fi
如果[-n“$check_performed”-a-z“$check_success”];然后
echo“无需运行测试。”
出口0
fi
移位1#删除'testname'参数
评估“$*”
用于添加包裹测试的CMake宏:

CMakeLists.txt

# 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 "$*"
# 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)
#类似于add_test(),但测试是用我们的包装器执行的。
函数(添加测试名称命令)
if(名称STREQUAL“名称”)
#复杂的add_test()命令流:NAME命令。。。
集合(其他参数${ARGN})
列表(在其他参数0处删除)#命令关键字
#实际'command'参数
列表(获取其他参数0 real_命令)
列表(删除其他参数0处的参数)
#如果'real_command'是目标,则需要将其转换为可执行文件的路径。
if(目标实数命令)
#生成器表达式在这里是完全正确的。

set(real_command“$如果您的测试成功生成了一个文件,那么让它依赖于unitTest可执行文件来完成大部分工作。@Jarod42但我如何将其与CTest联系起来?我对CTest和CMake如何交互仍有点模糊…只是将其作为自定义目标放在CMake中会起作用,但会完全失去CTest功能。您说过”400测试可执行文件”(通过这一点,我理解了400 main)因此,您可以有选择地从这些可执行文件运行。使用CTest,我只能运行可执行文件-要么全部,要么上次失败的全部。我无法让它重新运行所有已更改的成功可执行文件。我可以使用cmake中的自定义命令或类似命令,或者通过修改参数来执行此操作,但关键是不要手动执行。
ctest
命令接受多个参数,这些参数会影响要运行的测试集。例如,“-R”-按名称筛选测试,“-L”"-按标签筛选测试。可能,使用仪表板相关选项,您也可以选择要运行的测试。至于根据更改的可执行文件生成这些选项的值,您可以编写程序或脚本。仅运行选定测试可执行文件的另一种方法是将每个可执行文件包装到脚本中,脚本仅在特定条件下运行可执行文件已应用此选项。谢谢。*.sh也可以是任何脚本语言。使用此选项后,我可以将其移植到多平台的CMake脚本。CMake显然已安装;)