Xircuit Blog

Produkt-Updates, Entwickler-Logs und Neuigkeiten aus der Entwicklung von Xircuit.

Vertrauen durch Tests: eine Prod-E2E-Suite gegen die Live-Plattform cover image

Vertrauen durch Tests: eine Prod-E2E-Suite gegen die Live-Plattform


Vertrauen durch Tests: eine Prod-E2E-Suite gegen die Live-Plattform

Qualitätsprüfung als Sinnbild für Tests Foto: Kristin Hardwick · StockSnap (CC0 1.0), via Openverse

Es gibt einen Moment nach jedem Deployment, in dem ich kurz den Atem anhalte. Die Pipeline ist grün, alle Unit-Tests bestanden, die Container laufen — und trotzdem weiß ich in diesem Augenblick nicht mit letzter Sicherheit, ob sich ein echter Mensch bei Xircuit anmelden und eine Messung eintragen kann. Unit-Tests prüfen die Bausteine. Sie sagen nichts darüber, ob das Zusammenspiel aus Auth0, Blazor-Frontend, API und Datenbank in der Produktion tatsächlich funktioniert.

Diese Woche geht es um genau diese Lücke und darum, wie ich sie mit einer End-to-End-Suite geschlossen habe, die nicht gegen eine lokale Attrappe testet, sondern gegen die laufende Live-Plattform. Es ist die unbequemere Variante, und genau deshalb ist sie so aussagekräftig.

Warum gegen die Live-Umgebung testen?

Die meisten E2E-Suiten laufen gegen eine frisch hochgefahrene Testinstanz mit In-Memory-Datenbank und gemocktem Login. Das ist schnell und deterministisch, hat aber einen blinden Fleck: Es beweist, dass mein Code in sich stimmt, nicht dass die Produktion steht. Genau dort passieren die teuren Fehler — ein falsch gesetzter Redirect in der Auth0-Konfiguration, ein abgelaufenes Zertifikat, ein Container, der nach dem Deployment nicht sauber hochkommt.

Deshalb steuert die Prod-E2E-Suite mit Playwright einen echten Browser gegen die Live-Plattform. Sie ruft keine gemockte Anmeldeseite auf, sondern durchläuft die echte Auth0-Anmeldung: Formular ausfüllen, absenden, Callback abwarten, Session-Cookie prüfen. Was der Test sieht, ist exakt das, was ein Nutzer sieht. Wenn dieser Weg funktioniert, funktioniert er wirklich — und nicht nur unter Laborbedingungen.

Der Preis dafür ist Verantwortung. Ein Test, der echte Requests gegen die Produktion schickt und dort Daten anlegt, ist ein scharfes Werkzeug. Es braucht Leitplanken, damit daraus kein Datenmüll oder, schlimmer, ein versehentlicher Eingriff in echte Kundendaten wird.

Streng opt-in — der Sicherheitsschalter

Die wichtigste dieser Leitplanken ist Zurückhaltung als Standardverhalten. Die Suite ist streng opt-in: Ohne die passenden gesetzten Umgebungsvariablen überspringt jeder einzelne Test und fasst nichts an. Kein Login, kein Request, keine angelegte Entität. Wer die Tests laufen lassen will, muss bewusst die Persona-Zugangsdaten und die Ziel-Basis-URL in die Umgebung legen — es passiert nichts aus Versehen.

Diese Entscheidung hat einen sehr konkreten Hintergrund. Genau dieselben Testklassen liegen im Repository wie jede andere Testsuite auch, und sie werden im normalen dotnet test-Lauf mit eingesammelt. Würden sie unbedingt loslaufen, würde jede Continuous-Integration-Pipeline und jeder Entwickler auf seiner Maschine ungewollt Requests gegen die Produktion feuern. Der Opt-in-Schalter verhindert das, indem er die Abwesenheit von Konfiguration als klares „Nein" interpretiert.

Im CI ist die Suite zusätzlich abgeschaltet — ein zweiter, unabhängiger Riegel. Selbst wenn dort einmal versehentlich Umgebungsvariablen gesetzt würden, liefe die Prod-E2E-Suite nicht mit dem regulären Build. Sie ist etwas, das ich bewusst und gezielt anstoße, meist nach einem Deployment, nicht etwas, das im Hintergrund unkontrolliert mitläuft. Zwei Riegel statt einem, weil bei Schreibzugriffen auf die Produktion Vorsicht keine Übertreibung ist.

Jede Testentität hat einen Besitzer

Wenn ein Test schreibend gegen die echte Datenbank arbeitet, muss jederzeit klar sein, was Testdaten sind und was nicht. Sonst vermischt sich Künstliches mit Echtem, und irgendwann traut man sich nicht mehr aufzuräumen, weil man nicht mehr sicher unterscheiden kann.

Deshalb folgt jede angelegte Entität denselben drei Regeln. Sie gehört einer definierten Test-Persona — einem eigens dafür eingerichteten Konto, nicht einem echten Nutzer. Sie ist auf Datenebene als Testdaten markiert, sodass eine Abfrage sie eindeutig herausfiltern kann. Und sie trägt zusätzlich einen Marker direkt im Text, was die Zuordnung selbst dann trivial macht, wenn man nur in die Oberfläche schaut. Diese Redundanz aus struktureller Markierung und sichtbarem Marker ist bewusst: Sie erlaubt es, Testdaten sowohl automatisiert als auch mit bloßem Auge sofort zu erkennen.

Zahnräder als Sinnbild für Automatisierung Foto: Joe deSousa · StockSnap (CC0 1.0), via Openverse

Restlos aufräumen, vorher und nachher

Markieren allein reicht nicht — die Daten müssen auch wieder verschwinden. Dafür gibt es einen gated Cleanup-Endpunkt, der vor und nach jedem Lauf greift und die Testdaten restlos entfernt. „Gated" heißt: Der Endpunkt löscht ausschließlich Entitäten, die als Testdaten markiert sind und einer Test-Persona gehören. Echte Kundendaten liegen außerhalb seiner Reichweite, konstruktionsbedingt.

Dass der Cleanup nicht nur nach dem Lauf, sondern auch davor ausgeführt wird, hat sich als eine der nützlicheren Entscheidungen erwiesen. Bricht ein Test einmal mittendrin ab — Timeout, Netzwerkhänger, ein unerwartetes Dialogfenster — bleiben Reste zurück. Der vorgeschaltete Cleanup fegt diese Altlasten weg, bevor der nächste Durchlauf startet. So beginnt jeder Lauf auf sauberem Grund und ist nicht von den Trümmern des letzten abhängig. In der Praxis heißt das: Ich kann die Suite anstoßen, ohne mich zu fragen, in welchem Zustand die Produktion vom letzten Mal ist.

Von der Anmeldung zur ganzen Plattform

Am Anfang stand ein bescheidenes Ziel: beweisen, dass sich eine Persona anmelden und eine Handvoll Kernaktionen ausführen kann. Das war der Kern, der den Deployment-Moment entschärfen sollte. Doch sobald das Gerüst aus Opt-in, Personas, Markern und Cleanup stand, war die teure Arbeit erledigt — jeder weitere Testfall kostete nur noch wenig.

Also wuchs die Abdeckung. Aus wenigen Anmelde-Checks wurde ein Rendering-Smoke über hunderte Routen: Jede Seite wird aufgerufen, gerendert und daraufhin geprüft, dass sie ohne Fehler durchläuft. Das fängt eine überraschend große Klasse von Problemen ab — eine Route, die nach einem Refactoring ins Leere zeigt, eine Komponente, die unter Live-Daten in eine Ausnahme läuft, ein fehlendes Berechtigungssignal. Darüber hinaus kamen CRUD- und Interaktions-Mutationen hinzu: Tests, die nicht nur schauen, ob eine Seite lädt, sondern aktiv Datensätze anlegen, verändern und wieder entfernen und dabei den vollen Weg über echte Formulare, Dialoge und API-Aufrufe gehen.

Rückblickend war die Reihenfolge richtig. Hätte ich mit dem Anspruch begonnen, die halbe Plattform abzudecken, wäre ich an den Leitplanken gescheitert, bevor der erste Test grün war. Erst das kleine, sichere Fundament — und dann die Breite darauf.

Was die Suite mir tatsächlich gibt

Der eigentliche Gewinn ist kein Zahlenwert in einem Report, sondern eine Veränderung im Kopf. Nach einem Deployment stoße ich die Suite an, und wenn sie grün ist, weiß ich nicht nur, dass mein Code kompiliert — ich weiß, dass ein Browser sich real angemeldet, Seiten geladen, Daten geschrieben und wieder gelöscht hat, alles gegen die laufende Produktion. Der angehaltene Atem vom Anfang wird zu einem ruhigen Ausatmen.

Ehrlich bleiben will ich trotzdem: Eine solche Suite ist langsamer und fragiler als reine Unit-Tests, weil sie von der Verfügbarkeit externer Systeme abhängt. Ein hängender Auth0-Dienst oder eine Netzwerkschwankung kann einen Lauf rot färben, ohne dass etwas an meinem Code falsch wäre. Das ist der Preis dafür, die Wirklichkeit zu testen statt eine Nachbildung. Für mich ist er es wert.

Was kommt als Nächstes?

Nächste Woche: der öffentliche Auftritt — eine Marketing-Website mit Branchen-Seiten, Zielgruppen-Router und Zweisprachigkeit.


Kommentare

Noch keine Kommentare. Teilen Sie als Erste(r) Ihre Gedanken!

Kommentar hinterlassen