paint-brush
Einrichten einer perfekt isolierten End-to-End-Umgebungvon@marcinwosinek
511 Lesungen
511 Lesungen

Einrichten einer perfekt isolierten End-to-End-Umgebung

von Marcin Wosinek5m2023/04/12
Read on Terminal Reader
Read this story w/o Javascript

Zu lang; Lesen

Flaky-Tests sind Tests, die aus Gründen fehlschlagen, die nichts mit Ihrem Code zu tun haben. In extremen Fällen wird Ihr Team durch unzuverlässige Tests lernen, E2E-Ergebnisse zu ignorieren. Dadurch kann der Aufwand für die Automatisierung der Qualitätskontrolle (QS) zunichte gemacht werden. Der hier vorgestellte Ansatz befasst sich mit zwei großen Quellen potenzieller Probleme bei Ihren Testläufen.
featured image - Einrichten einer perfekt isolierten End-to-End-Umgebung
Marcin Wosinek HackerNoon profile picture

Für stabile End-to-End-Tests (E2E) benötigen wir eine möglichst von außen isolierte Umgebung.

Schuppenbildung reduzieren

Flaky-Tests sind Tests, die aus Gründen fehlschlagen, die nichts mit Ihrem Code zu tun haben. Sie erschweren den Einsatz von E2E als zuverlässige Prüfung der Richtigkeit des Antrags. In extremen Fällen wird Ihr Team durch unzuverlässige Tests lernen, E2E-Ergebnisse zu ignorieren. Dies kann den Aufwand für die Automatisierung der Qualitätskontrolle (QS) zunichtemachen.


Der hier vorgestellte Ansatz geht auf zwei große Ursachen potenzieller Probleme in Ihren Testläufen ein:


  • Vom Backend gespeicherter Zustand, der von verschiedenen Testjobs gemeinsam genutzt wird, und


  • Externe Dienste, über die Sie keine Kontrolle haben.


Es gibt andere Ursachen für Schuppenbildung, die von diesem Ansatz nicht betroffen sind:


  • Das wahre Problem liegt in der Anwendung, die zufällig aufgetaucht ist, oder


  • Probleme in der Anwendung werden durch die unnatürliche Geschwindigkeit verursacht, mit der E2E mit ihr interagiert.

Alternative

Bevor mein Team und ich meine Tests mit einem dedizierten Backend-Container durchführten, verwendeten wir einen unserer Nicht-Produktionsserver. Dieser Ansatz war in der Experimentierphase unserer E2E-Lösung in Ordnung.


Als es nur wenige Tests gab, konnten wir die Testergebnisse ohnehin nicht für Entscheidungen nutzen.


Als wir jedoch immer mehr Tests hinzufügten und längere Ausführungszeiten generierten, begann dieser Ansatz zu scheitern. Die Hauptprobleme waren wie folgt:


  • Obwohl wir versucht haben, die Datenänderungen innerhalb des Tests rückgängig zu machen, hinterließen einige Testfehler unerwartete Änderungen.


  • Parallele Jobs kollidierten. Verschiedene Testjobs änderten dieselben Zustände, was häufig dazu führte, dass einer der Jobs fehlschlug.

Dockerisieren Sie alles

Eine Lösung für dieses Problem bestand darin, für jeden Testauftrag einen separaten Backend-Server und eine separate Datenbank bereitzustellen. Ohne Docker wäre dieser Ansatz eine große Herausforderung.


Docker-Container sind ein perfektes Werkzeug zum Erstellen einer geschlossenen Umgebung mit allem, was eine Anwendung zum Ausführen benötigt:


  • Das richtige Betriebssystem (oder besser gesagt die richtige Linux-Distribution),


  • die Systemabhängigkeiten, wie Bildbearbeitungsbibliotheken usw., und


  • Die richtige Version von Sprachinterpretern (Python, Node usw.) oder Datenbankservern.

Datenbank

Für Ihren Test können Sie einen dedizierten Datenbankcontainer vorbereiten, der vorhersehbare Testdaten enthält. Auf diese Weise können Sie den Startpunkt bei jeder E2E-Ausführung exakt reproduzieren und Ihre Tests stabiler machen.


Sie können für Ihr Docker-Image verschiedene Tags verwenden, um die Testdatenbank zu versionieren. Dieselbe Testdatenbank kann auch in einer Entwicklungsumgebung verwendet werden. Für manuelle Tests in der Entwicklung benötigen Sie ähnliche Beispielentitäten wie für automatisierte Tests.

Backend

Wenn Sie Docker bereits für die Bereitstellung Ihres Backends verwendet haben, ist es ziemlich einfach, dasselbe Image für die Ausführung Ihres E2E wiederzuverwenden. In meinem Team stellen wir ein Backend als Container bereit und stellen Datenbank-URLs und Anmeldeinformationen als Umgebungsvariablen bereit.


Dieselbe Containerversion kann in der Produktion bereitgestellt oder in der kontinuierlichen Integration (CI) zum Ausführen von Tests verwendet werden – jede Umgebung bietet die richtigen Werte für die Verbindung mit der Datenbank.

Frontend

Abhängig von Ihrer Bereitstellungsstrategie können Sie einen der folgenden Schritte ausführen:


  1. Verwenden Sie die von Ihnen erstellten Container als Teil des Frontend-Builds.


  2. Holen Sie sich die kompilierten Dateien und stellen Sie sicher, dass sie für die Tests über HTTP verfügbar sind.


In unserem Fall verwenden wir Option 2: Wir stellen die Anwendung als statische Dateien bereit, also haben wir einfach einen dedizierten Container erstellt, um die erstellten Dateien während der E2E-Jobausführung bereitzustellen.

Jobdienste in GitLab

Wir nutzen GitLab als Plattform zum Betrieb unserer CI. Jeder Job in GitLab wird in einem Container mit einem Image Ihrer Wahl ausgeführt. Neben dem Hauptcontainer können Sie Dienste definieren: Zusätzliche Container, die neben Ihren Tests ausgeführt werden. Die Konfiguration ist so einfach wie:

 <job-name>: services: - name: <image> alias: <container-url>


Die verfügbaren Optionen ähneln denen in Docker Compose, sind jedoch eingeschränkter.

Ein „Fallstrick“ in der GitLab-Konfiguration besteht darin, die Variable FF_NETWORK_PER_BUILD auf 1 zu setzen, wenn Sie den Diensten während des Testlaufs erlauben möchten, aufeinander zuzugreifen.

Berücksichtigen Sie Ad-hoc-Daten zur Isolation am Arbeitsplatz

Irgendwann haben wir alle Tests parallel in einem Job ausgeführt. Damals war es notwendig, eine noch stärkere Isolierung durchzusetzen – jeder Test nutzte dasselbe Backend und dieselbe Datenbank.


Um dieses Problem zu umgehen, haben wir unsere Tests so aktualisiert, dass sie hauptsächlich auf den Zufallsdaten basieren, die wir direkt in den before Abschnitt der Tests einfügen. Dadurch konnten Tests unabhängig von anderen Änderungen in anderen Threads ausgeführt werden.


Dieser Ansatz kann zunächst etwas schwierig sein, kann aber je nach Ihren Umständen sinnvoll sein.

Räumen Sie nach jedem Test auf

Obwohl wir für jeden Testauftrag eine neue Datenbank erstellen, versuchen wir dennoch, dass unsere Tests die Anwendung in demselben Zustand verlassen, in dem sie sie vorgefunden haben. Vielleicht ist es ein Überbleibsel aus der Zeit, als wir Tests in einer gemeinsamen Umgebung durchgeführt haben.


Es ist nicht mehr entscheidend, kann aber in den folgenden Fällen während der Testentwicklung dennoch hilfreich sein:


  • Wenn Sie nur einen Test ausführen, unterscheidet sich der Status, auf den der Test trifft, nicht von dem, wenn Sie alle Tests in der Datei ausführen.


  • Wenn Sie den gleichen Test immer wieder lokal ausführen, damit die Datenbank durch die früheren Ausführungen nicht beeinträchtigt wird

Falscher externer Dienst

Es gibt Fälle, in denen das Verschieben von Diensten in einen Container keine Option ist. Zum Beispiel:


  • Wenn es externe Server gibt, die die Anwendung direkt oder über einen Backend-Proxy nutzt, oder


  • Sie besitzen Server, die aufgrund technischer Probleme nicht in einem Container ausgeführt werden können.


In beiden Fällen können Sie zum Isolieren der Testläufe die Anforderungen verspotten, die an diese Dienste gehen. Dadurch wird verhindert, dass unvorhersehbare externe Dienste Ihre Testergebnisse beeinflussen. Ein Nachteil dieses Ansatzes besteht darin, dass Ihre Tests vom Kontext, in dem Ihre Anwendungen ausgeführt werden, abgekoppelt werden.


Wenn Mocks vorhanden sind, erkennen Ihre Tests keine Fälle, in denen sich Änderungen an diesen Diensten auf Ihre Anwendung auswirken.

Lernen Sie weiter

Wenn Sie mehr über Tests oder andere programmbezogene Themen erfahren möchten, können Sie sich hier anmelden, um Updates zu erhalten, wenn ich verwandte Inhalte veröffentliche.