2016-01-11 2 views
2

Je travaille sur une grande base de code qui compte près de 400 exécutables de test, avec des temps d'exécution variant entre 0,001 seconde et 1800 secondes. Quand un peu de code change CMake reconstruira intelligemment seulement les cibles qui ont changé, prenant plusieurs fois plus court que le test réel prendra. La seule façon dont je sais autour de cela est de filtrer manuellement sur les tests que vous savez que vous souhaitez exécuter. Mon intuition dit que je voudrais ré-exécuter n'importe quelle suite de tests qui n'a pas une exécution réussie stockée - soit parce qu'elle a échoué, ou parce qu'elle a été recompilée.Exécuter uniquement des tests modifiés ou échoués avec CMake/CTest?

Est-ce possible? Si c'est le cas, comment?

+0

Si votre test génère un fichier en cas de succès, faites en sorte que l'exécutable unitTest fasse la plupart du travail. – Jarod42

+0

@ Jarod42 Mais comment lier cela à CTest? Je suis encore un peu vague sur la façon dont CTest et CMake interagissent ... Le simple fait de le mettre dans CMake en tant que cible personnalisée fonctionnerait, mais perdrait complètement la fonctionnalité CTest. – dascandy

+0

Vous avez dit que vous avez "400 exécutables de test" (par ce que je comprends 400 principal) de sorte que vous exécutez sélectivement à partir de ces exécutables. – Jarod42

Répondre

3

ctest command accepte plusieurs paramètres, ce qui affecte l'ensemble des tests à exécuter. Par exemple. , "- R" - filtre les tests par leur nom, "-L" - filtre les tests par étiquette. Probablement, en utilisant des options liées au tableau de bord, vous pouvez également choisir des tests à exécuter. En ce qui concerne la génération de valeurs pour ces options en fonction des exécutables modifiés, vous pouvez écrire un programme ou un script, qui vérifie le temps de modification des exécutables et/ou analyse le dernier fichier journal pour trouver les tests ayant échoué. Une autre façon d'exécuter uniquement les exécutables modifiés consiste à placer les tests dans un script supplémentaire. Ce script ne pourra être exécuté que si certaines conditions sont satisfaites.

pour le script wrapper Linux pourrait être mis en œuvre comme suit:

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 "$*" 

macro CMake pour ajouter essai emballé:

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) 

Lorsque vous voulez exécuter uniquement les tests qui ont été executables changé depuis la dernière course ou qui a été échoué la dernière fois, utilisez

LAST_LOG_FILE=<build-dir>/Testing/Temporary/LastTest.log \ 
LAST_FAILED_LOG_FILE=<build-dir>/Testing/Temporary/LastTestsFailed.log \ 
ctest 

Tous les autres tests seront automatiquement transmis.