Unsere Abteilung erstellt vollautomatische Pipelines für die Ausgabe neuer Versionen von Anwendungen an die Produktionsumgebung. Dies erfordert natürlich automatisierte Funktionstests. Unter dem Strich - die Geschichte, wie wir, angefangen beim Testen in einem Thread auf dem lokalen Computer, mit dem Allure-Bericht auf GitLab-Seiten zum Multithread-Start von Selbsttests für Selenoid in der Assembly-Pipeline kamen und als Ergebnis ein cooles Automatisierungstool erhielten, das zukünftige verwenden können Teams.

Wo haben wir angefangen?
Um Autotests zu implementieren und in die Pipeline zu integrieren, brauchten wir ein Framework für die Automatisierung, das flexibel an unsere Anforderungen angepasst werden kann. Idealerweise wollte ich einen einzigen Standard für die Autotest-Engine erhalten, der zum Einbetten von Autotests in eine Pipeline geeignet ist. Für die Implementierung haben wir folgende Technologien ausgewählt:
- Java
- Maven
- Selen
- Gurke + JUNIT 4,
- Allure
- Gitlab

Warum so ein Set? Java ist eine der beliebtesten Sprachen für Autotests. Darüber hinaus sprechen alle Mitglieder des Teams es. Selen ist die offensichtliche Lösung. Gurke sollte unter anderem das Vertrauen der an manuellen Tests beteiligten Einheiten in die Ergebnisse von Autotests stärken.
Single-Threaded-Tests
Um das Rad nicht neu zu erfinden, haben wir die 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 ein Gold-Image aufnehmen und darin Tests entwickeln, um es an sein Projekt anzupassen. Wir haben die GitLab-CI-Bank bereitgestellt, auf der wir Folgendes konfiguriert haben:
- tägliche Durchläufe aller schriftlichen Autotests für jedes Projekt;
- wird in der Assembly-Pipeline gestartet.
Anfangs gab es nur wenige Tests, und sie gingen in einem Strom. Der Single-Thread-Start auf dem GitLab Windows-Runner war für uns recht zufriedenstellend: Die Tests belasteten den Prüfstand nur geringfügig und verbrauchten fast keine Ressourcen.
Im Laufe der Zeit wurden Autotests immer häufiger, und wir dachten darüber nach, sie parallel auszuführen, als ein vollständiger Lauf ungefähr drei Stunden dauerte. Es gab andere Probleme:
- wir konnten nicht sicherstellen, dass die Tests stabil sind;
- Tests, die mehrere Läufe hintereinander auf dem lokalen Computer durchliefen, fielen manchmal in CI.
Beispiel für die Einrichtung eines 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>
Beispiel für einen Allure-Bericht
Runner Load während der Tests (8 Kerne, 8 GB RAM, 1 Thread)Pluspunkte von Single-Threaded-Tests:
- einfach zu konfigurieren und auszuführen;
- Starts in CI unterscheiden sich praktisch nicht von lokalen Starts.
- Tests beeinflussen sich nicht gegenseitig;
- Mindestanforderungen an die Läuferressourcen.
Nachteile von Single-Threaded-Tests:
- sehr langfristig;
- lange Stabilisierung der Tests;
- Ineffiziente Nutzung der Runner-Ressourcen, extrem geringe Auslastung.
JVM-Gabeltests
Da wir uns bei der Implementierung des
Basisframeworks nicht um threadsicheren Code gekümmert haben, wurde das
cucumber-jvm-parallel-plugin für Maven zum naheliegendsten Weg, parallel zu laufen. Das Plugin ist einfach zu konfigurieren, aber für den korrekten parallelen Betrieb der Autotests müssen Sie es in separaten Browsern ausführen. Nichts zu tun, ich musste Selenoid verwenden.
Der Selenoid-Server wurde auf einem Computer mit 32 Kernen und 24 GB RAM gestartet. Das Limit wurde in 48 Browsern festgelegt - 1,5 Threads pro Kern und ca. 400 MB RAM. Infolgedessen wurde die Testzeit von drei Stunden auf 40 Minuten reduziert. Die Beschleunigung der Läufe half, das Stabilisierungsproblem zu lösen: Jetzt konnten wir 20 bis 30 Mal schnell neue Autotests durchführen, bis wir sicher waren, dass sie stabil durchgeführt wurden.
Der erste Nachteil der Lösung war die hohe Auslastung der Runner-Ressourcen mit einer geringen Anzahl paralleler Threads: Auf 4 Kernen und 8 GB RAM funktionierten die Tests stabil in nicht mehr als 6 Threads. Das zweite Minus: Das Plugin generiert Runner-Klassen für jedes Szenario, egal wie viele ausgeführt werden.
Wichtig! Werfen Sie beispielsweise keine Variable mit Tags in
argLine wie
folgt :
<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. Versuchen Sie also, alle Tests auszuführen, überspringen Sie sie direkt nach dem Start und erstellen Sie viele JVM-Gabeln.
Es ist richtig, die Variable mit dem Tag in den Plugin-Einstellungen in
Tags zu werfen (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
Ein Beispiel für eine Testlaufzeit, wenn Sie das Tag direkt an
mvn übergeben ... –Dcucumber.options :
[INFO] Total time: 44.467 s
Beispiel für die Einrichtung eines 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>**
Ein Beispiel für einen Allure-Bericht (der instabilste Test, 4 Rerana)
Runner Load während der Tests (8 Kerne, 8 GB RAM, 12 Threads)Vorteile:
- einfache Einrichtung - Sie müssen nur das Plugin hinzufügen;
- die Fähigkeit, gleichzeitig eine große Anzahl von Tests durchzuführen;
- schnellere Stabilisierung der Tests dank Anspruch 1.
Nachteile:
- mehrere Betriebssysteme / Container erforderlich;
- hoher Ressourcenverbrauch pro Gabel;
- Das Plugin ist veraltet und wird nicht mehr unterstützt.
Wie man Instabilität besiegt
Prüfstände sind nicht perfekt, ebenso wie die Autotests selbst. Es überrascht nicht, dass wir eine Reihe von Flacky-Tests erhalten haben. Das
Maven-todsichere Plugin kam zur
Rettung , das
sofort den Neustart gefallener 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 als Argument für Maven übergeben.
Beispiel für die Einrichtung eines 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 ...Alternativ können Sie die Maven-Optionen für das PowerShell-Skript (PS1) festlegen:
Set-Item Env:MAVEN_OPTS "-Dfile.encoding=UTF-8 -Dsurefire.rerunFailingTestsCount=2"
Vorteile:
- Sie müssen keine Zeit damit verschwenden, einen instabilen Test zu analysieren, wenn er abstürzt.
- Sie können die Stabilitätsprobleme des Prüfstands ausgleichen.
Nachteile:
- Sie können schwebende Fehler überspringen.
- Laufzeit wird erhöht.
Parallele Tests mit der Cucumber 4-Bibliothek
Die Anzahl der Tests wuchs von Tag zu Tag. Wir haben noch einmal darüber nachgedacht, die Läufe zu beschleunigen. Außerdem wollte ich so viele Tests wie möglich in die Pipeline-Baugruppe der Anwendung integrieren. Ein kritischer Faktor war die zu lange Generation von Läufern, wenn sie parallel mit dem Maven-Plugin ausgeführt wurden.
Cucumber 4 wurde zu diesem Zeitpunkt bereits veröffentlicht, daher haben wir beschlossen, den Kernel für diese Version neu zu schreiben. In den Versionshinweisen wurde uns ein paralleler Start auf Thread-Ebene versprochen. Theoretisch hätte dies sein sollen:
- Beschleunigen Sie die Ausführung von Autotests erheblich, indem Sie die Anzahl der Threads erhöhen.
- Schließen Sie den Zeitverlust für die Generierung von Läufern für jeden Autotest aus.
Die Optimierung des Frameworks für Multithread-Autotests war nicht so schwierig. Cucumber 4 führt jeden einzelnen Test von Anfang bis Ende in einem dedizierten Thread aus, sodass einige häufig verwendete statische Dinge einfach in ThreadLocal-Variablen konvertiert wurden.
Die Hauptsache beim Konvertieren mit Idea Refactoring-Tools besteht darin, die Stellen zu überprüfen, an denen die Variable verglichen wurde (z. B. die Überprüfung auf Null). Darüber hinaus müssen Sie das Allure-Plugin in den Anmerkungen der Junit Runner-Klasse rendern.
Beispiel für die Einrichtung eines 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>
Beispiel eines Allure-Berichts (der instabilste Test, 5 Wiederholungen)
Runner Load während der Tests (8 Kerne, 8 GB RAM, 24 Threads)Vorteile:
- geringer Ressourcenverbrauch;
- native Unterstützung von Cucumber - keine zusätzlichen Tools erforderlich;
- die Fähigkeit, mehr als 6 Threads auf dem Prozessorkern auszuführen.
Nachteile:
- Sie müssen sicherstellen, dass der Code die Ausführung mit mehreren Threads unterstützt.
- Eintrittsschwelle erhöht.
Allure-Berichte auf GitLab-Seiten
Nach der Einführung des Multithread-Starts haben wir viel mehr Zeit mit der Analyse von Berichten verbracht. Zu diesem Zeitpunkt mussten wir jeden Bericht als Artefakt in GitLab hochladen, dann herunterladen und entpacken. Es ist nicht sehr bequem und lang. Und wenn jemand anderes den Bericht zu Hause sehen möchte, muss er die gleichen Operationen ausführen. Wir wollten schneller Feedback bekommen und es gab einen Ausweg - GitLab-Seiten. Dies ist eine integrierte Funktion, die in allen neueren Versionen von GitLab sofort verfügbar ist. Ermöglicht das Bereitstellen statischer Sites auf Ihrem Server und den Zugriff auf diese über einen direkten Link.
Alle Screenshots mit Allure-Berichten wurden auf GitLab-Seiten erstellt. Das Skript zum Bereitstellen des Berichts auf GitLab-Seiten befindet sich in Windows PowerShell (zuvor müssen Sie Autotests ausführen):
New-Item -ItemType directory -Path $testresult\history | 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 $buildlocation\target\site\allure-maven-plugin\* $buildlocation\public /s /i /Y
Was ist das Ergebnis
Wenn Sie also darüber nachgedacht haben, ob Sie Thread-sicheren Code im Cucumber-Autotest-Framework benötigen, liegt die Antwort auf der Hand - mit Cucumber 4 ist es einfach, ihn zu implementieren, wodurch die Anzahl der gleichzeitig gestarteten Threads erheblich erhöht wird. Bei dieser Testmethode geht es bereits um die Leistung der Maschine mit Selenoid und Prüfstand.
Die Praxis hat gezeigt, dass das Ausführen von automatischen Tests für Threads den Ressourcenverbrauch bei bester Leistung minimieren kann. Wie aus den Diagrammen ersichtlich ist, führt eine zweifache Erhöhung der Durchflüsse nicht zu einer ähnlichen Beschleunigung beim Bestehen von Leistungstests. Trotzdem konnten wir der Anwendungsbaugruppe mehr als 200 automatische Tests hinzufügen, die selbst mit 5 Wiederholungen in etwa 24 Minuten abgeschlossen sind. Auf diese Weise erhalten Sie schnelles Feedback von ihnen und können bei Bedarf Änderungen vornehmen und den Vorgang erneut wiederholen.