Zum Inhalt springen

Suchen...

Testen von Microservices

Aus einem trägen Monolithen mit stundenlangen End-to-End-Tests zu schnellen Microservices: Welche Teststrategie dabei wirklich funktioniert.

Aktualisiert: 11 Min. Lesezeit
Cover zum Expertengespräch über 'Testen von Microservices' mit Michael Kutz und Richard Seidl.

Microservices testen bedeutet, automatisierte Tests auf drei Ebenen zu verteilen: Unit-Tests für Geschäftslogik, API-Tests auf Service-Ebene und reduzierte End-to-End-Tests für den wichtigsten Nutzungspfad. Flaky Tests werden konsequent entfernt oder stabilisiert. Produktionsmonitoring und Alerting ersetzen dabei aufwändige Testumgebungen, weil schnelle Rollbacks das Fehlerrisiko pro Release klein halten.

Das Wichtigste in Kürze

  • Microservices lösen kein technisches Problem, sondern ein organisatorisches: Wer Conway’s Law zum Architekturprinzip macht, skaliert Teams, nicht nur Code.
  • Eine reine End-to-End-Test-Suite mit mehreren Stunden Laufzeit ist kein Sicherheitsnetz, sondern ein Wartungsproblem, das die gesamte Entwicklungsgeschwindigkeit bremst.
  • Flaky Tests konsequent in Quarantäne schicken und die verantwortlichen Teams direkt ansprechen ist ein wirksamer Weg, eine aufgeblähte Testsuite schrittweise zu bereinigen.
  • Shift-right durch Monitoring und Alerting kann End-to-End-Tests auf Teststages teilweise ersetzen, weil ein schneller Rollback im E-Commerce günstiger ist als aufwendige Testumgebungen für seltene Produktionsfehler.

Warum aus dem Monolithen Microservices wurden

Der Auslöser für Microservices ist selten technisch, sondern organisatorisch. Bei REWE stand am Anfang ein monolithischer Onlineshop, der an viele Legacy-Systeme angebunden war und über Jahre unter Zeitdruck chaotisch gewachsen war. Der Code sollte modularisiert und wartbar gemacht werden, gleichzeitig sollten viele Teams parallel daran arbeiten.

Genau das ist im Monolithen schwierig. Michael Kutz beschreibt die “Merge-Hölle”, in der einer eine Datei refactored hat und drei andere dasselbe anders gemacht haben. Am Ende stehen hundert geänderte Dateien und niemand weiß, welche Version gewinnt.

Microservices lösen dieses Problem, indem sie Conway’s Law zum Architekturprinzip machen. Teams bekommen klar abgegrenzte Verantwortungsbereiche und können unabhängig voneinander deployen. Der Preis dafür sind neue Probleme: Koordination, API-Management zwischen Services und eine komplexere Code-Organisation.

Technisch machen Microservices eigentlich keinen Sinn. Es ist ein organisatorisches Problem, das du auf eine technische Ebene hebst. Und bei dem “nur” sehe ich den Fehler im Satz, denn in der IT ist alles ein organisatorisches Problem.

Michael Kutz

Lange End-to-End-Tests bremsen jede schnelle Entwicklung

Wer ein System fast ausschließlich über End-to-End-Tests absichert, bezahlt das mit langen Laufzeiten und schwacher Aussagekraft. Die Testsuite des alten Monolithen lief drei bis vier Stunden, selbst nach Optimierungen noch gut zwei Stunden.

Hinter dieser Testarchitektur steckt ein nachvollziehbares Muster. Wenn sich ein System ständig stark verändert, schreiben Entwickler ungern Unit-Tests mit vielen Details, weil diese Details sich dauernd ändern. Sie konzentrieren sich stattdessen auf das Stabile: den End-to-End-Test, der das Requirement direkt prüft.

Das Ziel war ein anderes. Nach dem Vorbild von Extreme Programming wollte das Team innerhalb von rund zehn Minuten wissen, ob eine Änderung etwas kaputt gemacht hat. Stunden später ein rotes Lämpchen zu sehen, passt dazu nicht.

Besonders teuer war die Fehleranalyse. Ein gefailter End-to-End-Test liefert zuerst nur ein rotes Signal, aber keine Information über die Ursache. Oft lag es an einer langsamen Datenbank zum falschen Zeitpunkt, also an etwas, wofür der gerade deployte Code nichts konnte.

Drei Mal rot heißt erst dann echter Fehler

Eine ehrliche, wenn auch unschöne Metrik aus der Praxis: Ein Test wurde erst dann als echter Fehler behandelt, wenn er drei Mal hintereinander rot war. Es war wirtschaftlich einfacher, die Suite erneut laufen zu lassen, als nach jedem einzelnen Fehlschlag die Ursache zu suchen.

Diese Pragmatik ist kein Vorbild, aber sie zeigt das Grundproblem flakiger End-to-End-Tests. Wenn die Analyse teurer ist als ein erneuter Lauf, verliert der Test seinen Wert als Frühwarnsystem. Du testest dann eher die Stabilität deiner Infrastruktur als deinen Code.

Wie Microservices schrittweise aus dem Monolithen herausgelöst werden

Der Weg aus dem Monolithen folgte dem Strangler-Fig-Pattern. Der bestehende Code wurde als gegeben angenommen und nicht mehr angefasst, weil jede Änderung das zementierte Konstrukt destabilisiert hätte. Die Annahme, dieser Code sei fehlerfrei, stimmt nie, war aber die Arbeitsgrundlage.

Funktionen wurden nach und nach durch Code in Microservices ersetzt. Aus dem Monolithen führte ein Bypass in den neuen Service, der die Funktion übernahm. Die ersten Services waren im Kern Datenbanken mit APIs, also kaum Businesslogik, sondern vor allem Datenhaltung, die die komplexe Datenbankstruktur des Monolithen kapselte.

Danach wurde die Businesslogik schrittweise über diese Services gezogen. Am Ende blieb im Monolithen nur noch das Rendern des HTML. Eine bewusste Architekturentscheidung war dabei der Wechsel zu asynchronen APIs, auch wenn Eventual Consistency und End-to-End-Tests nicht gut zusammenpassen.

So baust du eine echte Testpyramide auf

Jeder neue Microservice bekam von Anfang an eine sauber formulierte API und dafür eigene Tests. Mit dem Test-Tooling von Spring Boot wurde nur der einzelne Service hochgefahren und die API konsequent durchgetestet, ohne in die interne Implementierung zu schauen. Parallel entstanden Unit-Tests für die Stellen mit Businesslogik.

So wuchs nach und nach eine pyramidenartige Teststruktur. Was lange fehlte, war eine gute Spitze. Die alte Gesamttestsuite blieb das End-to-End-Niveau, und für sie waren alle verantwortlich. Wenn alle für etwas verantwortlich sind, ist es am Ende meistens niemand.

Die Reduktion der End-to-End-Tests folgte einer klaren Logik. Wo eine Funktionalität auf API-Ebene oder im Unit-Test bereits abgesichert war, brauchte es nicht zehn End-to-End-Varianten desselben Falls. Ein Test pro Risiko genügt, wenn das Risiko weiter unten in der Pyramide bereits abgedeckt ist.

Quarantäne statt Pflege: wie flakige Tests aussortiert werden

Bei vielen Teams lässt sich eine geteilte Testsuite nicht mehr zentral pflegen. Aus vier bis sechs Teams wurden zwölf bis vierzehn. Wo anfangs eine Art Gilde gemeinsam an der Suite arbeitete, kümmerten sich später nur noch Vereinzelte.

Die Lösung war ein einfacher Mechanismus. Ein Test, der beim ersten Versuch failt, ging in Quarantäne. Das vermutlich verantwortliche Team wurde gebeten, ihn zu stabilisieren, weil flakige Tests nicht erwünscht sind.

Oft kam die Antwort, dass das Team den Test gar nicht kannte und nicht mehr brauchte. Auf diese Weise schrumpfte die Suite organisch: Die stabilen Tests blieben, der Rest fiel raus. Irgendwann wurde sie komplett neu geschrieben.

Die neue Suite testete bewusst nur noch den Money Path. Statt vieler einzelner Given-When-Then-Fälle entstand ein fortlaufender Test, der den Happy Path durchläuft und genau dort bricht, wo etwas nicht stimmt. Das macht die Eingrenzung des Fehlers leichter.

Shift left, but look right: Tests verlagern und Produktion beobachten

Die wirksamste Ergänzung zu kleineren Tests ist gute Beobachtbarkeit in Produktion. Das Team verfolgte zwei Bewegungen. Zuerst Shift Left: Tests wurden kleiner und auf eine niedrigere Ebene geschoben, um früher Feedback zu bekommen.

Dann kam “shift left, but look right”. Logging und Observability wurden ausgebaut, vor allem aber Monitoring und Alerting. Die Regel: Sobald ein Kunde eine Fehlermeldung sieht, soll irgendwo eine rote Lampe angehen. Ausgenommen sind reine Netzwerkprobleme, etwa wenn jemand in der Bahn durch einen Tunnel fährt.

Häufig releasen senkt das Risiko pro Deployment. Sehr viele kleine Änderungen bedeuten, dass jedes einzelne Release wenig kaputt machen kann. Die wochenlangen Abnahmetests des Monolithen wurden überflüssig.

Diese Verlagerung verändert die Rolle der End-to-End-Tests. Für ein E-Commerce-Geschäft kann es genügen, im Zweifel auf Produktion zu deployen, den Alert abzuwarten und bei Bedarf zurückzurollen. Der Aufwand, jeden seltenen Fehler vorab auf einer Teststage nachzustellen, steht in keinem Verhältnis zum möglichen Schaden.

Warum Rollback-Fähigkeit keine Kür ist

Ohne sauberen Deployment-Mechanismus funktioniert dieser Ansatz nicht. Bei einer Microservice-Umstellung musst du Teile des Systems ständig neu deployen, ohne Downtime. Das erzwingt Verfahren wie Blue-Green-Deployment oder Canary Releasing.

Einige Lektionen bleiben schmerzhaft. Datenbankmigrationen brauchen in diesem Kontext deutlich mehr Aufmerksamkeit und Sorgfalt. Der Gewinn ist trotzdem groß: die Fähigkeit, etwas auf Produktion zu deployen und dort zu prüfen, ob es funktioniert.

Wer den Rollback nicht leben kann, baut stattdessen oft riesige Testumgebungen mit hohem Energieaufwand. Das ist häufig der teurere Weg, der die eigentliche Lücke nur kaschiert.

Saubere Tests motivieren weniger, als man denkt

Schnelleres Feedback motiviert, das Aufräumen von Tests selten. Entwickler freuen sich, wenn sie die Laufzeit der Testsuite halbieren, denn dann geht alles spürbar schneller. Einen großen End-to-End-Test durch sechs Unit-Tests zu ersetzen, macht dagegen kaum jemandem Spaß.

Der Grund liegt in der Haltung vieler Entwickler. Sie wollen Code schreiben, der Probleme löst, nicht Code, der Probleme schafft. Ein failender Test wird zunächst als Problem empfunden, nicht als Hilfe. Anwälte guter Testcode-Qualität sind seltener, als die meisten annehmen.

Daraus folgt ein praktischer Rat. Wenn du Testqualität verbessern willst, knüpfe sie an einen spürbaren Nutzen wie kürzere Laufzeiten und schnelleres Feedback. Reines Aufräumen ohne sichtbaren Gewinn setzt sich schwer durch.

Aufräumen braucht denselben Plan wie Feature-Arbeit

Clean-up-Sprints scheitern oft daran, dass niemand sie plant. Die Zeit ist immer gleichzeitig zu viel und zu wenig: Das ganz große Chaos räumst du nie auf, und meistens willst du es auch gar nicht.

Michael vergleicht es mit einem Kinderzimmer. Sag jemandem, er solle aufräumen, und die erste Frage ist: Wo soll ich anfangen? Es ist zu groß und ohne Struktur.

Der Denkfehler liegt in der Erwartung, man habe für das Aufräumen ohnehin schon einen Plan. Hat man nicht, weil man im Feature-Modus steckt. Technische Schulden abzubauen verlangt denselben planerischen Aufwand wie Feature-Entwicklung. Ohne diesen Plan verpufft die geschenkte Zeit.

Warum Testdatenqualität das härteste End-to-End-Problem bleibt

Die größte offene Baustelle ist nicht die Testtechnik, sondern die Datenversorgung auf den Stages. Hunderte Märkte mit unterschiedlichen Sortimenten, unterschiedliche logistische Organisationen und eine unüberschaubare Zahl an Konfigurationen müssen abgebildet werden.

Lieferlager, die Privatkunden direkt beliefern, arbeiten teils anders als andere Standorte, und der IT-Prozess muss diese Varianten abbilden. Eine Umgebung bereitzustellen, die jederzeit alle Varianten liefert, ist aufwändig.

Hier zeigt sich, warum hauptamtliche Tester wieder gebraucht werden. Lange gab es bei REWE keine Tester, sondern nur Entwicklungsteams, die testeten. Heute gibt es einige sehr gute Tester, die end-to-end prüfen, teils mit den mobilen Devices, mit denen Mitarbeiter im Lager arbeiten. Diese Geräte hat nicht jeder Entwickler auf dem Tisch.

Exploratives Testen gehört in die Entwicklungsteams

Eine konkrete Empfehlung lautet, exploratives Testen direkt in den Teams zu verankern. Ein Entwicklungsteam sollte sich auch mal eine halbe Stunde im Sprint nehmen, um das eigene Produkt gezielt auf Herz und Nieren zu prüfen.

Eine gute Charter entsteht oft aus dem Code selbst. Beim Lesen einer API fällt einem Entwickler auf, dass die Autorisierung womöglich nicht so funktioniert, wie sie sollte. Genau solche internen Unstimmigkeiten lassen sich explorativ schnell aufdecken.

Fachlich einfach, technisch komplex: die Falle der Legacy-Systeme

Manche Anforderungen sind fachlich trivial und technisch überraschend kompliziert. Aus fachlicher Sicht ist eine Änderung leicht, technisch ist sie es nicht. Michael ordnet das klar ein: Dinge, die fachlich einfach sind, dürfen technisch eigentlich nicht so komplex sein.

Die Ursache liegt in der Historie. Legacy-Systeme, die schon dreimal umgebaut wurden und durch vier Teams gegangen sind, lassen sich nur schwer anpassen. Sowohl Plattform-Engineers als auch die Fachseite müssen oft abgeholt werden, wo das eigentliche Testproblem liegt.

Eine gut geschnittene Microservice- und Datenarchitektur zahlt sich gerade bei externem Druck aus. Die Mehrwertsteuersenkung ließ sich überraschend schnell umsetzen, weil die Datenarchitektur das hergab. Auch regulatorische Änderungen gehen schneller, wenn Organisationsstruktur und Code gut zusammenpassen.

Häufig gestellte Fragen

Lösen Microservices ein technisches Problem?

Nein. Der Auslöser ist meist organisatorisch: Viele Teams sollen parallel an einem Codebestand arbeiten, ohne sich gegenseitig zu blockieren. Im Monolithen endet das in der Merge-Hölle, wenn vier Leute dieselbe Datei unterschiedlich refactoren. Microservices machen Conway’s Law zum Architekturprinzip: klar abgegrenzte Verantwortung, unabhängiges Deployment. Der Preis sind Koordination, API-Management und komplexere Code-Organisation.

Was sagt es aus, wenn ein Test erst nach drei roten Läufen ernst genommen wird?

Es zeigt, dass die Testsuite ihren Wert als Frühwarnsystem verloren hat. In der beschriebenen Praxis war es wirtschaftlich einfacher, die Suite nochmals laufen zu lassen, als nach jedem Fehlschlag die Ursache zu suchen. Häufig lag es an einer langsamen Datenbank zum falschen Zeitpunkt. Getestet wird dann eher die Stabilität der Infrastruktur als der Code.

Wie löst man einen gewachsenen Monolithen schrittweise auf?

Über das Strangler-Fig-Pattern: Der bestehende Code bleibt unangetastet, weil jede Änderung das zementierte Konstrukt destabilisiert. Aus dem Monolithen führt ein Bypass in den neuen Service, der eine Funktion übernimmt. Die ersten Services waren im Kern Datenbanken mit APIs, die die komplexe Datenbankstruktur kapselten. Erst danach wanderte die Businesslogik nach, bis im Monolithen nur das Rendern des HTML blieb.

Wie viele End-to-End-Tests braucht ein Service wirklich?

Einen Test pro Risiko, sofern das Risiko weiter unten in der Pyramide bereits abgedeckt ist. Wenn eine Funktionalität auf API-Ebene oder im Unit-Test abgesichert ist, sind zehn End-to-End-Varianten desselben Falls überflüssig. Die neu geschriebene Suite prüfte bewusst nur noch den Money Path, und zwar als fortlaufenden Test, der genau an der fehlerhaften Stelle bricht.

Wie bekommt man eine aufgeblähte, geteilte Testsuite wieder klein?

Über Quarantäne statt Pflege. Ein Test, der beim ersten Versuch failt, geht in Quarantäne, und das vermutlich verantwortliche Team wird gebeten, ihn zu stabilisieren. Oft kannte das Team den Test gar nicht und brauchte ihn nicht mehr. So schrumpft die Suite organisch. Hintergrund war ein Wachstum von vier bis sechs auf zwölf bis vierzehn Teams, das zentrale Pflege unmöglich machte.

Können Monitoring und Alerting End-to-End-Tests ersetzen?

Teilweise ja. Die Regel lautet: Sobald ein Kunde eine Fehlermeldung sieht, geht irgendwo eine rote Lampe an, ausgenommen reine Netzwerkprobleme wie eine Tunnelfahrt. Für ein E-Commerce-Geschäft kann es genügen, auf Produktion zu deployen, den Alert abzuwarten und bei Bedarf zurückzurollen. Jeden seltenen Fehler vorab auf einer Teststage nachzustellen, steht in keinem Verhältnis zum möglichen Schaden.

Welche Voraussetzungen braucht es, um Fehler erst in Produktion zu finden?

Einen sauberen Deployment-Mechanismus ohne Downtime, also Verfahren wie Blue-Green-Deployment oder Canary Releasing. Datenbankmigrationen brauchen dabei deutlich mehr Aufmerksamkeit und Sorgfalt. Wer den Rollback nicht leben kann, baut stattdessen oft riesige Testumgebungen mit hohem Energieaufwand: häufig der teurere Weg, der die eigentliche Lücke nur kaschiert.

Warum scheitern Clean-up-Sprints für Testcode so oft?

Weil niemand sie plant. Technische Schulden abzubauen verlangt denselben planerischen Aufwand wie Feature-Entwicklung, doch im Feature-Modus existiert dieser Plan nicht, und die geschenkte Zeit verpufft. Dazu kommt die Motivationslage: Eine halbierte Testlaufzeit freut jeden, einen großen End-to-End-Test durch sechs Unit-Tests zu ersetzen kaum jemanden. Knüpfe Testqualität deshalb an spürbaren Nutzen wie schnelleres Feedback.

Diese Seite teilen