Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB

Notre division crée des pipelines entièrement automatiques pour lancer de nouvelles versions d'applications dans l'environnement de production. Bien entendu, cela nécessite des tests fonctionnels automatisés. Sous la coupe se trouve une histoire sur la façon dont, en commençant par des tests monothread sur une machine locale, nous avons atteint le point de test automatique multithread exécuté sur Selenoid dans le pipeline de construction avec un rapport Allure sur les pages GitLab et avons finalement obtenu un outil d'automatisation sympa. que les futurs gens pourront utiliser des équipes.

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB

Par où avons-nous commencé ?

Pour mettre en œuvre les autotests et les intégrer dans le pipeline, nous avions besoin d'un cadre d'automatisation pouvant être modifié de manière flexible pour répondre à nos besoins. Idéalement, je souhaitais obtenir une norme unique pour le moteur de test automatique, adaptée à l'intégration des tests automatiques dans le pipeline. Pour la mise en œuvre, nous avons choisi les technologies suivantes :

  • Java
  • Maven,
  • Sélénium,
  • Concombre+JUNIT 4,
  • Séduire,
  • GitLab.

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB

Pourquoi cet ensemble en particulier ? Java est l'un des langages les plus populaires pour les tests automatisés, et tous les membres de l'équipe le parlent. Le sélénium est la solution évidente. Le concombre, entre autres, était censé accroître la confiance dans les résultats des tests automatisés de la part des services impliqués dans les tests manuels.

Tests à thread unique

Afin de ne pas réinventer la roue, nous avons pris comme base pour le framework les développements de différents référentiels sur GitHub et les avons adaptés nous-mêmes. Nous avons créé un référentiel pour la bibliothèque principale avec le cœur du framework d'autotest et un référentiel avec un exemple Gold d'implémentation d'autotests sur notre noyau. Chaque équipe a dû prendre l'image Gold et y développer des tests, en l'adaptant à son projet. Nous l'avons déployé sur la banque GitLab-CI, sur laquelle nous avons configuré :

  • exécutions quotidiennes de tous les autotests écrits pour chaque projet ;
  • lancements dans le pipeline de construction.

Au début, il y avait peu de tests et ils étaient effectués en un seul flux. L'exécution monothread sur le runner Windows GitLab nous convenait plutôt bien : les tests chargeaient très légèrement le banc de test et n'utilisaient quasiment aucune ressource.

Au fil du temps, le nombre d'autotests est devenu de plus en plus nombreux et nous avons pensé à les exécuter en parallèle, lorsqu'une exécution complète a commencé à prendre environ trois heures. D'autres problèmes sont également apparus :

  • nous n'avons pas pu vérifier que les tests étaient stables ;
  • les tests exécutés plusieurs fois de suite sur la machine locale plantaient parfois dans CI.

Exemple de mise en place d'autotests :

<plugins>
	
<plugin>
    	
<groupId>org.apache.maven.plugins</groupId>
    	
<artifactId>maven-surefire-plugin</artifactId>
    	
<version>2.20</version>
    	
<configuration>
        	
<skipTests>${skipTests}</skipTests>
        	
<testFailureIgnore>false</testFailureIgnore>
        	
<argLine>
            	
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
            	
-Dcucumber.options="--tags ${TAGS} --plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm --plugin pretty"
        	
</argLine>
    	
</configuration>
	
    <dependencies>
        	
<dependency>
            	
<groupId>org.aspectj</groupId>
            	
<artifactId>aspectjweaver</artifactId>
            	
<version>${aspectj.version}</version>
        	
</dependency>
    	
</dependencies>
	
</plugin>
	
<plugin>
    	
<groupId>io.qameta.allure</groupId>
    	
<artifactId>allure-maven</artifactId>
    	
<version>2.9</version>
	
</plugin>
</plugins>

 Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB
Exemple de rapport Allure

 Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB
Charge du coureur pendant les tests (8 cœurs, 8 Go de RAM, 1 thread)
 
Avantages des tests monothread :

  • facile à installer et à exécuter ;
  • les lancements en CI ne sont pratiquement pas différents des lancements locaux ;
  • les tests ne s'affectent pas les uns les autres ;
  • exigences minimales pour les ressources de coureur.

Inconvénients des tests monothread :

  • prendre beaucoup de temps à terminer ;
  • longue stabilisation des tests ;
  • utilisation inefficace des ressources du coureur, utilisation extrêmement faible.

Tests sur les forks JVM

Puisque nous n'avons pas pris en compte le code thread-safe lors de l'implémentation du framework de base, la manière la plus évidente d'exécuter en parallèle était concombre-jvm-plugin-parallèle pour Maven. Le plugin est facile à configurer, mais pour un fonctionnement parallèle correct, les autotests doivent être exécutés dans des navigateurs séparés. Il n'y a rien à faire, j'ai dû utiliser Selenoid.

Le serveur Selenoid a été lancé sur une machine dotée de 32 cœurs et de 24 Go de RAM. La limite a été fixée à 48 navigateurs – 1,5 threads par cœur et environ 400 Mo de RAM. En conséquence, la durée du test a été réduite de trois heures à 40 minutes. L'accélération des exécutions a permis de résoudre le problème de stabilisation : nous pouvions désormais exécuter rapidement de nouveaux autotests 20 à 30 fois jusqu'à ce que nous soyons sûrs qu'ils s'exécutaient de manière fiable.
Le premier inconvénient de la solution était l'utilisation élevée des ressources d'exécution avec un petit nombre de threads parallèles : sur 4 cœurs et 8 Go de RAM, les tests s'exécutaient de manière stable sur 6 threads maximum. Deuxième inconvénient : le plugin génère des classes de runner pour chaque scénario, quel que soit le nombre d'entre eux lancés.

Important! Ne transmettez pas de variable avec des balises à lignearg, par exemple, comme ceci :

<argLine>-Dcucumber.options="--tags ${TAGS} --plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm --plugin pretty"</argLine>
…
Mvn –DTAGS="@smoke"

Si vous transmettez la balise de cette manière, le plugin générera des exécuteurs pour tous les tests, c'est-à-dire qu'il essaiera d'exécuter tous les tests, en les ignorant immédiatement après le lancement et en créant de nombreux forks JVM.

Il est correct de lancer une variable avec une balise dans étiquettes dans les paramètres du plugin, voir exemple ci-dessous. D'autres méthodes que nous avons testées rencontrent des problèmes pour connecter le plugin Allure.

Exemple de durée d'exécution de 6 tests courts avec des réglages incorrects :

[INFO] Total time: 03:17 min

Exemple de durée d'exécution du test si vous transférez directement le tag vers mvn... –Dcucumber.options:

[INFO] Total time: 44.467 s

Exemple de mise en place d'autotests :

<profiles>
	
<profile>
    	
<id>parallel</id>
    	
<build>
        	
<plugins>
            	
<plugin>
                	
<groupId>com.github.temyers</groupId>
                	
<artifactId>cucumber-jvm-parallel-plugin</artifactId>
                	
<version>5.0.0</version>
                	
<executions>
                    	
<execution>
                        	
<id>generateRunners</id>
                        	
<phase>generate-test-sources</phase>
                        	
<goals>
                            	
<goal>generateRunners</goal>
                        	
</goals>
                        	
<configuration>
                	
            <tags>
                            	
<tag>${TAGS}</tag>
                            	
</tags>
                            	
<glue>
                                	
<package>stepdefs</package>
                            	
</glue>
                        	
</configuration>
     	
               </execution>
                	
</executions>
    	
        </plugin>
            	
<plugin>
                	
<groupId>org.apache.maven.plugins</groupId>
                	
<artifactId>maven-surefire-plugin</artifactId>
        	
        <version>2.21.0</version>
                	
<configuration>
                    	
<forkCount>12</forkCount>
                    	
<reuseForks>false</reuseForks>
                    	
<includes>**/*IT.class</includes>
                   	
 <testFailureIgnore>false</testFailureIgnore>
                    	
<!--suppress UnresolvedMavenProperty -->
                    	
<argLine>
  	
 -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" -Dcucumber.options="--plugin io.qameta.allure.cucumber2jvm.AllureCucumber2Jvm TagPFAllureReporter --plugin pretty"
                    	
</argLine>
                	
</configuration>
                	
<dependencies>
                    	
<dependency>
                        	
<groupId>org.aspectj</groupId>
                        	
<artifactId>aspectjweaver</artifactId>
                        	
<version>${aspectj.version}</version>
                 	
   </dependency>
                	
</dependencies>
         	
   </plugin>
        	
</plugins>
    	
</build>
	
</profile>

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTB
Exemple de rapport Allure (le test le plus instable, 4 relances)

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTBCharge du coureur pendant les tests (8 cœurs, 8 Go de RAM, 12 threads)
 
Avantages:

  • configuration facile - il vous suffit d'ajouter un plugin ;
  • la capacité d'effectuer simultanément un grand nombre de tests ;
  • accélération de la stabilisation du test grâce à l'étape 1. 

Inconvénients:

  • Plusieurs systèmes d'exploitation/conteneurs requis ;
  • consommation élevée de ressources pour chaque fork ;
  • Le plugin est obsolète et n'est plus pris en charge. 

Comment surmonter l'instabilité 

Les bancs de tests ne sont pas idéaux, tout comme les autotests eux-mêmes. Il n’est pas surprenant que nous soyons confrontés à un certain nombre de tests irréguliers. Je suis venu à la rescousse plugin maven infaillible, qui prend en charge le redémarrage des tests ayant échoué. Vous devez mettre à jour la version du plugin vers au moins 2.21 et écrire une ligne avec le nombre de redémarrages dans le fichier pom ou la transmettre comme argument à Maven.

Exemple de mise en place d'autotests :

   	
<plugin>
        	
<groupId>org.apache.maven.plugins</groupId>
  	
      <artifactId>maven-surefire-plugin</artifactId>
        	
<version>2.21.0</version>
        	
<configuration>
           	
….
            	
<rerunFailingTestsCount>2</rerunFailingTestsCount>
            	
….
            	
</configuration>
</plugin>

Ou au démarrage : mvn… -Dsurefire.rerunFailingTestsCount=2…
En option, définissez les options Maven pour le script PowerShell (PS1) :

  
Set-Item Env:MAVEN_OPTS "-Dfile.encoding=UTF-8 -Dsurefire.rerunFailingTestsCount=2"

Avantages:

  • pas besoin de perdre du temps à analyser un test instable lorsqu’il plante ;
  • les problèmes de stabilité du banc d’essai peuvent être atténués.

Inconvénients:

  • les défauts flottants peuvent être manqués ;
  • le temps d'exécution augmente.

Tests parallèles avec la bibliothèque Cucumber 4

Le nombre de tests augmentait chaque jour. Nous avons encore pensé à accélérer les courses. De plus, je souhaitais intégrer autant de tests que possible dans le pipeline d'assemblage d'applications. Le facteur critique était que la génération des coureurs prenait trop de temps lors d'une exécution en parallèle à l'aide du plugin Maven.

A cette époque, Cucumber 4 était déjà sorti, nous avons donc décidé de réécrire le noyau pour cette version. Dans les notes de version, on nous promettait un lancement parallèle au niveau des threads. Théoriquement, cela aurait dû être :

  • accélérer considérablement l'exécution des autotests en augmentant le nombre de threads ;
  • éliminez la perte de temps liée à la génération de coureurs pour chaque autotest.

L'optimisation du cadre pour les autotests multithreads ne s'est pas avérée si difficile. Cucumber 4 exécute chaque test individuel sur un thread dédié du début à la fin, de sorte que certaines éléments statiques courants ont été simplement convertis en variables ThreadLocal. 
L'essentiel lors de la conversion à l'aide des outils de refactoring Idea est de vérifier les endroits où la variable a été comparée (par exemple, en vérifiant null). De plus, vous devez ajouter le plugin Allure à l'annotation de classe Junit Runner.

Exemple de mise en place d'autotests :

 
<profile>
	
<id>parallel</id>
	
<build>
    	
<plugins>
        	
<plugin>
            	
<groupId>org.apache.maven.plugins</groupId>
 	
           <artifactId>maven-surefire-plugin</artifactId>
            	
<version>3.0.0-M3</version>
   	
         <configuration>
                	
<useFile>false</useFile>
                	
<testFailureIgnore>false</testFailureIgnore>
        	
        <parallel>methods</parallel>
                	
<threadCount>6</threadCount>
                	
<perCoreThreadCount>true</perCoreThreadCount>
                	
<argLine>
                    	
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                	
</argLine>
            	
</configuration>
            	
<dependencies>
                	
<dependency>
                    	
<groupId>org.aspectj</groupId>
   	
                 <artifactId>aspectjweaver</artifactId>
                    	
<version>${aspectj.version}</version>
                	
</dependency>
            	
</dependencies>
        	
</plugin>
    	
</plugins>
	
</build>
</profile>

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTBExemple de rapport Allure (le test le plus instable, 5 relances)

Implémenter, faire évoluer : expérience de l'utilisation de tests automatisés chez VTBCharge du coureur pendant les tests (8 cœurs, 8 Go de RAM, 24 threads)

Avantages:

  • faible consommation de ressources;
  • prise en charge native de Cucumber - aucun outil supplémentaire requis ;
  • la possibilité d'exécuter plus de 6 threads par cœur de processeur.

Inconvénients:

  • vous devez vous assurer que le code prend en charge l'exécution multithread ;
  • le seuil d’entrée augmente.

Rapports Allure sur les pages GitLab

Après avoir introduit l’exécution multithread, nous avons commencé à consacrer beaucoup plus de temps à l’analyse des rapports. À cette époque, nous devions télécharger chaque rapport en tant qu'artefact sur GitLab, puis le télécharger et le décompresser. Ce n'est pas très pratique et prend beaucoup de temps. Et si quelqu'un d'autre souhaite consulter le rapport par lui-même, il devra alors effectuer les mêmes opérations. Nous voulions recevoir des commentaires plus rapidement et nous avons trouvé une solution : les pages GitLab. Il s'agit d'une fonctionnalité intégrée disponible immédiatement dans toutes les versions récentes de GitLab. Permet de déployer des sites statiques sur votre serveur et d'y accéder via un lien direct.

Toutes les captures d'écran des rapports Allure ont été prises sur les pages GitLab. Script de déploiement du rapport sur les pages GitLab - dans Windows PowerShell (avant cela, vous devez exécuter des autotests) :

New-Item -ItemType directory -Path $testresulthistory | Out-Null

try {Invoke-WebRequest -Uri $hst -OutFile $outputhst}
Catch{echo "fail copy history"}
try {Invoke-WebRequest -Uri $hsttrend -OutFile $outputhsttrnd}
Catch{echo "fail copy history trend"}

mvn allure:report
#mvn assembly:single -PzipAllureReport
xcopy $buildlocationtargetsiteallure-maven-plugin* $buildlocationpublic /s /i /Y

Avec le résultat que 

Donc, si vous vous demandez si vous avez besoin d'un code Thread Safe dans le framework de test automatique Cucumber, la réponse est désormais évidente : avec Cucumber 4, il est facile de l'implémenter, augmentant ainsi considérablement le nombre de threads lancés simultanément. Avec cette méthode de réalisation de tests, la question porte sur les performances de la machine avec Selenoid et le banc de test.

La pratique a montré que l'exécution d'autotests sur les threads vous permet de réduire au minimum la consommation de ressources avec les meilleures performances. Comme le montrent les graphiques, le doublement des threads ne conduit pas à une accélération similaire dans les tests de performances. Cependant, nous avons pu ajouter plus de 2 tests automatisés à la version de l'application, qui, même avec 200 réexécutions, s'exécutent en 5 minutes environ. Cela vous permet de recevoir un retour rapide de leur part et, si nécessaire, d'apporter des modifications et de répéter la procédure.

Source: habr.com

Ajouter un commentaire