Évaluation de la couverture de test d'un projet Java en utilisant Apache Ignite comme exemple

Je participe au développement du projet open source Apache Ignite , tout en travaillant sur le projet, il est devenu intéressant pour moi d'évaluer la couverture du test et c'est ce qui en est ressorti.



La couverture des tests est la mesure la plus utilisée pour évaluer la qualité des tests de produits.


C'est l'une des rares métriques qui vous permet d'identifier les domaines qui nécessitent une attention en raison du risque de manquer une erreur, et également de prioriser le travail sur les modules ou les composants du projet.


Le moyen le plus simple d'obtenir un rapport d'évaluation de la couverture de test Java complet pour votre projet est d'utiliser le programme de couverture intégré à IntelliJ IDEA . Il vous permet de configurer une collection de métriques en quelques clics et d'exécuter des tests avec la génération de rapport suivante.


Test dans le projet Apache Ignite


Le projet Apache Ignite utilise son propre cadre de test pour les tests, implémenté sur la base de JUnit 3. Au moment de la rédaction, le module de projet principal contient ~ 82 000 tests, dont la plupart sont des composants et nécessitent de soulever un cluster à partir de plusieurs nœuds, y compris différentes machines virtuelles Java. avec préparation concomitante de l'environnement.


Il convient de noter qu'assurer l'opérabilité d'une base de régression aussi énorme n'est pas une tâche facile. La communauté surveille en permanence l'état du produit et corrige les bogues trouvés dans le cadre de l' initiative Make Teamcity Green Again .


Les fonctionnalités de projet indiquées ne permettent pas d'exécuter tous les tests à la fois dans une seule machine virtuelle Java pour les raisons suivantes:


  • erreur possible OutOfMemoryError;
  • crash possible de la JVM;
  • impasses possibles;
  • incapacité à démarrer le test en raison d'un nœud non arrêté lors du test précédent;
  • la course prendra trois jours sur un ordinateur.

Tout cela rend impossible l'utilisation d' IntelliJ IDEA pour obtenir un rapport sur tous les tests du projet et nécessite une approche spéciale pour résoudre le problème.


Préparer et effectuer une évaluation de la couverture des tests


Sur la base du travail effectué, l'approche la plus fiable pour terminer la tâche a été choisie, comprenant les étapes suivantes:


  1. Définition d'un ensemble de classes de test;
  2. Exécution pour chaque classe de test:
    2.1. démarrer et exécuter un ensemble de tests de classe dans une machine virtuelle Java séparée avec un temporisateur de surveillance qui mettra fin au thread en cas de gel ou de problèmes avec les tests;
    2.2. les opérations d'obtention et d'enregistrement des métriques de couverture de test;
    2.3. nettoyer l'environnement à la fin des tests;
  3. Fusion de toutes les mesures obtenues au paragraphe 2;
  4. Génération de rapports complète.

Il existe de nombreux outils pour évaluer la couverture des tests, dont les plus populaires sont:



Je ne m'attarderai pas sur leurs différences; un tableau visuel comparant les capacités des outils d'évaluation de la couverture des tests est présenté ici .


Pour résoudre le problème, la bibliothèque JaCoCo a été choisie afin de pouvoir intégrer la solution sur TeamCity , sur laquelle repose l'infrastructure de test existante du projet Apache Ignite . TeamCity peut fonctionner hors de la boîte avec JaCoCo .


Pour automatiser l'algorithme décrit, un script bash et Maven ont été utilisés . La configuration du plugin Jacoco Maven est implémentée par un profil Maven distinct dans pom.xml.


Le profil de configuration du plugin JaCoCo est donné ci-dessous et implique une séparation en 2 démarrages distincts:


  1. Exécutez des tests avec l'agent JaCoCo ( prepare-agent ) connecté pour collecter les mesures de couverture de test. La propriété 'runDirectory' sera transmise par le script au démarrage, ce qui permettra d'enregistrer les résultats des exécutions isolément;
  2. Fusionner les résultats d'exécution ( fusion ) et la génération de rapport ( rapport ).

Configuration de Maven JaCoCo
<profile> <id>coverage</id> <properties> <argLine> -ea \ -server \ -Xms1g \ -Xmx6g \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:+AggressiveOpts \ -DIGNITE_UPDATE_NOTIFIER=false \ -DIGNITE_NO_DISCO_ORDER=true \ -DIGNITE_PERFORMANCE_SUGGESTIONS_DISABLED=true \ -DIGNITE_QUIET=false \ -Djava.net.preferIPv4Stack=true \ </argLine> <coverage.dataFile>${runDirectory}/coverage-reports/jacoco-ut.exec</coverage.dataFile> <coverage.outputDir>${runDirectory}/jacoco-ut</coverage.outputDir> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> </configuration> <executions> <execution> <id>default-test</id> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.1</version> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> <configuration> <destFile>${coverage.dataFile}</destFile> </configuration> </execution> <execution> <id>post-merge</id> <phase>validate</phase> <goals> <goal>merge</goal> </goals> <configuration> <fileSets> <fileSet> <directory>${basedir}</directory> <includes> <include>results/*/coverage-reports/jacoco-ut.exec</include> </includes> </fileSet> </fileSets> <destFile>merged.exe</destFile> </configuration> </execution> <execution> <id>generate-report</id> <phase>validate</phase> <goals> <goal>report</goal> </goals> <configuration> <dataFile>${basedir}/merged.exe</dataFile> <outputDirectory>${basedir}/coverage-report</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> 

Voici un script qui implémente les étapes décrites précédemment.


Script bash de contrôle
 #!/bin/bash #        DEVNOTES.txt # #    : ignite/modules/core # #   : 'nohup ./coverage.sh >/dev/null 2>&1 &' SCRIPT_DIR=$(cd $(dirname "$0"); pwd) echo "***** ." echo "*****   ..." tests=() while IFS= read -r -d $'\0'; do tests+=("$REPLY") done < <(find $SCRIPT_DIR/src/test/java/org/apache/ignite -type f -name "*Test*" ! -name "*\$*" ! -name "*Abstract*" ! -name "*TestSuite*" -print0) testsCount=${#tests[@]} echo "*****   ="$testsCount idx=0 for path in ${tests[@]} do idx=$((idx+1)) echo "*****  "$idx"  "$testsCount echo "*****  : "$path filename=$(basename -- "$path") filename="${filename%.*}" echo "*****  : "$filename runDir=$SCRIPT_DIR"/results/"$filename mkdir -p $runDir if [ "$(ls -A $runDir)" ]; then continue fi echo "*****  ..." timeout 30m mvn -P surefire-fork-count-1,coverage test -Dmaven.main.skip=true -Dmaven.test.failure.ignore=true -Dtest=$filename -DfailIFNoTests=false -DrunDirectory=$runDir echo "*****  ..." pkill java done #      mvn -X -P surefire-fork-count-1,coverage validate echo "***** ." 

L'exécution de tous les tests avec évaluation de la couverture a pris environ 50 heures sur un serveur dédié: 4 vCPU, 8RAM, 50 SSD, Ubuntu x64 16.04 .


L'approche décrite peut facilement être mise en parallèle avec plusieurs peuplements, si les ressources sont disponibles, ce qui réduira considérablement le temps d'exécution et permettra d'obtenir une évaluation de la couverture des tests. Après avoir intégré cette solution sur TeamCity , le temps d'évaluation de la couverture de test devrait prendre environ 2 heures.


Résultats


Selon les résultats du rapport, la couverture des instructions du projet est d'environ 61%.


Couverture des instructions pour les principaux composants:


  • Cache - 66%
  • Découverte - 57%
  • Calcul - 60%
  • Stream - 51%
  • Binaire - 68%
  • Transactions - 71%

Après avoir analysé les résultats, il est devenu évident que tout le code chaud était couvert, ainsi que le code pour résoudre les problèmes typiques. Avec une telle boîte à outils, il sera possible d'étendre la couverture à des situations rares et atypiques, ce qui rendra le produit encore plus fiable.


PS Rapport complet pour révision .

Source: https://habr.com/ru/post/fr413587/


All Articles