Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB

Unsere Abteilung erstellt vollautomatische Pipelines für die Einführung neuer Anwendungsversionen in die Produktionsumgebung. Dies setzt natürlich automatisierte Funktionstests voraus. Unter dem Ausschnitt finden Sie eine Geschichte darüber, wie wir, beginnend mit Single-Thread-Tests auf einem lokalen Computer, mit einem Allure-Bericht auf GitLab-Seiten den Punkt erreichten, an dem Multi-Thread-Autotest auf Selenoid in der Build-Pipeline ausgeführt wurde, und schließlich ein cooles Automatisierungstool erhielten dass zukünftige Menschen Teams nutzen können.

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB

Wo haben wir angefangen?

Um Autotests umzusetzen und in die Pipeline zu integrieren, benötigten wir ein Automatisierungsframework, das flexibel an unsere Bedürfnisse angepasst werden konnte. Idealerweise wollte ich einen einzigen Standard für die Autotest-Engine erhalten, der für die Einbettung von Autotests in die Pipeline angepasst ist. Für die Umsetzung haben wir folgende Technologien ausgewählt:

  • Java
  • Maven,
  • Selen,
  • Gurke+JUNIT 4,
  • Locken,
  • GitLab.

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB

Warum gerade dieses Set? Java ist eine der beliebtesten Sprachen für automatisierte Tests und wird von allen Teammitgliedern beherrscht. Selen ist die naheliegende Lösung. Cucumber sollte unter anderem das Vertrauen in die Ergebnisse automatisierter Tests seitens der mit manuellen Tests befassten Abteilungen stärken.

Single-Threaded-Tests

Um das Rad nicht neu zu erfinden, haben wir Entwicklungen aus verschiedenen Repositories auf GitHub als Grundlage für das Framework genommen und für uns angepasst. Wir haben ein Repository für die Hauptbibliothek mit dem Kern des Autotest-Frameworks und ein Repository mit einem Gold-Beispiel für die Implementierung von Autotests auf unserem Kern erstellt. Jedes Team musste das Gold-Image nehmen, darin Tests entwickeln und es an sein Projekt anpassen. Wir haben GitLab-CI in der Bank bereitgestellt und Folgendes konfiguriert:

  • tägliche Durchläufe aller schriftlichen Autotests für jedes Projekt;
  • wird in der Build-Pipeline gestartet.

Zunächst gab es nur wenige Tests, die in einem Stream durchgeführt wurden. Der Single-Thread-Betrieb auf dem Windows-Runner GitLab gefiel uns ganz gut: Die Tests belasteten den Prüfstand nur sehr gering und verbrauchten nahezu keine Ressourcen.

Im Laufe der Zeit wurde die Anzahl der Autotests immer zahlreicher und wir dachten darüber nach, sie parallel durchzuführen, als ein vollständiger Durchlauf etwa drei Stunden dauerte. Es traten auch andere Probleme auf:

  • wir konnten nicht überprüfen, ob die Tests stabil waren;
  • Tests, die mehrmals hintereinander auf dem lokalen Computer ausgeführt wurden, stürzten in CI manchmal ab.

Beispiel für die Einrichtung von 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>

 Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB
Beispiel für einen Allure-Bericht

 Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB
Runner-Auslastung während Tests (8 Kerne, 8 GB RAM, 1 Thread)
 
Vorteile von Single-Threaded-Tests:

  • einfach einzurichten und zu betreiben;
  • Einführungen in CI unterscheiden sich praktisch nicht von lokalen Einführungen;
  • Tests beeinflussen sich nicht gegenseitig;
  • Mindestanforderungen an Läuferressourcen.

Nachteile von Single-Threaded-Tests:

  • die Fertigstellung dauert sehr lange;
  • lange Stabilisierung der Tests;
  • ineffiziente Nutzung der Läuferressourcen, extrem geringe Auslastung.

Tests auf JVM-Forks

Da wir bei der Implementierung des Basisframeworks nicht auf threadsicheren Code geachtet haben, war die parallele Ausführung die naheliegendste Möglichkeit Gurke-JVM-Parallel-Plugin für Maven. Das Plugin ist einfach zu konfigurieren, für einen korrekten Parallelbetrieb müssen Autotests jedoch in separaten Browsern ausgeführt werden. Es gibt nichts zu tun, ich musste Selenoid verwenden.

Der Selenoid-Server wurde auf einer Maschine mit 32 Kernen und 24 GB RAM gestartet. Das Limit wurde auf 48 Browser festgelegt – 1,5 Threads pro Kern und etwa 400 MB RAM. Dadurch konnte die Testzeit von drei Stunden auf 40 Minuten verkürzt werden. Die Beschleunigung der Läufe trug zur Lösung des Stabilisierungsproblems bei: Jetzt konnten wir schnell 20 bis 30 Mal neue Autotests durchführen, bis wir sicher waren, dass sie zuverlässig liefen.
Der erste Nachteil der Lösung war die hohe Auslastung der Runner-Ressourcen bei einer geringen Anzahl paralleler Threads: Auf 4 Kernen und 8 GB RAM funktionierten die Tests stabil mit nicht mehr als 6 Threads. Der zweite Nachteil: Das Plugin generiert für jedes Szenario Runner-Klassen, egal wie viele davon gestartet werden.

Wichtig! Übergeben Sie keine Variable mit Tags an argLine, zum Beispiel so:

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

Wenn Sie das Tag auf diese Weise übergeben, generiert das Plugin Läufer für alle Tests, d. h. es versucht, alle Tests auszuführen, überspringt sie unmittelbar nach dem Start und erstellt viele JVM-Forks.

Es ist richtig, eine Variable mit einem Tag hineinzuwerfen Tags in den Plugin-Einstellungen, siehe Beispiel unten. Andere von uns getestete Methoden haben Probleme beim Verbinden des Allure-Plugins.

Beispiellaufzeit für 6 Kurztests mit falschen Einstellungen:

[INFO] Total time: 03:17 min

Beispiel einer Testlaufzeit, wenn Sie das Tag direkt übertragen mvn... –Dcucumber.options:

[INFO] Total time: 44.467 s

Beispiel für die Einrichtung von 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>

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTB
Beispiel eines Allure-Berichts (der instabilste Test, 4 Wiederholungen)

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTBRunner-Auslastung während Tests (8 Kerne, 8 GB RAM, 12 Threads)
 
Profis:

  • einfache Einrichtung – Sie müssen nur ein Plugin hinzufügen;
  • die Fähigkeit, eine große Anzahl von Tests gleichzeitig durchzuführen;
  • Beschleunigung der Teststabilisierung dank Schritt 1. 

Nachteile:

  • Mehrere Betriebssysteme/Container erforderlich;
  • hoher Ressourcenverbrauch für jede Gabel;
  • Das Plugin ist veraltet und wird nicht mehr unterstützt. 

Wie man Instabilität überwindet 

Prüfstände sind nicht ideal, ebenso wie die Autotests selbst. Es ist nicht verwunderlich, dass wir eine Reihe unzuverlässiger Tests haben. Kam zur Rettung Maven todsicheres Plugin, das standardmäßig den Neustart fehlgeschlagener Tests unterstützt. Sie müssen die Plugin-Version auf mindestens 2.21 aktualisieren und eine Zeile mit der Anzahl der Neustarts in die POM-Datei schreiben oder diese als Argument an Maven übergeben.

Beispiel für die Einrichtung von Autotests:

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

Oder beim Start: mvn … -Dsurefire.rerunFailingTestsCount=2 …
Legen Sie optional Maven-Optionen für das PowerShell-Skript (PS1) fest:

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

Profis:

  • Sie müssen keine Zeit mit der Analyse eines instabilen Tests verschwenden, wenn dieser abstürzt.
  • Stabilitätsprobleme des Prüfstands können gemildert werden.

Nachteile:

  • schwebende Defekte können übersehen werden;
  • Laufzeit erhöht sich.

Parallele Tests mit der Cucumber 4-Bibliothek

Die Zahl der Tests wuchs täglich. Wir haben erneut darüber nachgedacht, die Läufe zu beschleunigen. Darüber hinaus wollte ich möglichst viele Tests in die Application-Assembly-Pipeline integrieren. Ausschlaggebend war, dass die Generierung der Runner bei paralleler Ausführung mit dem Maven-Plugin zu lange dauerte.

Zu diesem Zeitpunkt war Cucumber 4 bereits veröffentlicht worden, daher haben wir uns entschieden, den Kernel für diese Version neu zu schreiben. In den Versionshinweisen wurde uns ein paralleler Start auf Thread-Ebene versprochen. Theoretisch hätte das sein sollen:

  • Beschleunigen Sie die Ausführung von Autotests erheblich, indem Sie die Anzahl der Threads erhöhen.
  • Eliminieren Sie den Zeitverlust beim Generieren von Läufern für jeden Autotest.

Die Optimierung des Frameworks für Multithread-Autotests erwies sich als nicht so schwierig. Cucumber 4 führt jeden einzelnen Test von Anfang bis Ende in einem dedizierten Thread aus, daher wurden einige gängige statische Dinge einfach in ThreadLocal-Variablen umgewandelt. 
Das Wichtigste bei der Konvertierung mit Idea-Refactoring-Tools besteht darin, die Stellen zu überprüfen, an denen die Variable verglichen wurde (z. B. auf Null prüfen). Darüber hinaus müssen Sie das Allure-Plugin zur Junit Runner-Klassenanmerkung hinzufügen.

Beispiel für die Einrichtung von 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>

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTBBeispiel eines Allure-Berichts (der instabilste Test, 5 Wiederholungen)

Implementieren, skalieren: Erfahrung im Einsatz automatisierter Tests bei VTBRunner-Auslastung während Tests (8 Kerne, 8 GB RAM, 24 Threads)

Profis:

  • geringer Ressourcenverbrauch;
  • native Unterstützung von Cucumber – keine zusätzlichen Tools erforderlich;
  • die Fähigkeit, mehr als 6 Threads pro Prozessorkern auszuführen.

Nachteile:

  • Sie müssen sicherstellen, dass der Code die Multithread-Ausführung unterstützt.
  • die Eintrittsschwelle steigt.

Allure-Berichte auf GitLab-Seiten

Nach der Einführung der Multithread-Ausführung verbrachten wir viel mehr Zeit mit der Analyse von Berichten. Damals mussten wir jeden Bericht als Artefakt auf GitLab hochladen, ihn dann herunterladen und entpacken. Das ist nicht sehr praktisch und dauert lange. Und wenn jemand anderes den Bericht selbst einsehen möchte, muss er die gleichen Vorgänge durchführen. Wir wollten schneller Feedback erhalten und haben eine Lösung gefunden: GitLab-Seiten. Dies ist eine integrierte Funktion, die in allen neueren Versionen von GitLab sofort verfügbar ist. Ermöglicht Ihnen die Bereitstellung statischer Sites auf Ihrem Server und den Zugriff darauf über einen direkten Link.

Alle Screenshots der Allure-Berichte wurden auf GitLab-Seiten erstellt. Skript zum Bereitstellen des Berichts auf GitLab-Seiten – in Windows PowerShell (zuvor müssen Sie Autotests ausführen):

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

Mit dem Ergebnis, dass 

Wenn Sie also darüber nachgedacht haben, ob Sie Thread-sicheren Code im Cucumber-Autotest-Framework benötigen, liegt die Antwort jetzt auf der Hand: Mit Cucumber 4 ist er einfach zu implementieren, wodurch die Anzahl der gleichzeitig gestarteten Threads erheblich erhöht wird. Bei dieser Art der Testdurchführung stellt sich die Frage nach der Leistung der Maschine mit Selenoid und dem Prüfstand.

Die Praxis hat gezeigt, dass Sie durch die Ausführung von Autotests für Threads den Ressourcenverbrauch bei bester Leistung auf ein Minimum reduzieren können. Wie aus den Grafiken ersichtlich ist, führt die Verdoppelung von Threads nicht zu einer ähnlichen Beschleunigung bei Leistungstests. Allerdings konnten wir der Anwendungserstellung mehr als 2 automatisierte Tests hinzufügen, die selbst bei fünf Wiederholungen in etwa 200 Minuten ausgeführt werden. Dadurch erhalten Sie von ihnen eine schnelle Rückmeldung und können bei Bedarf Änderungen vornehmen und den Vorgang noch einmal wiederholen.

Source: habr.com

Kommentar hinzufügen