Stabile Ende-zu-Ende-Tests für große, langlebige Anwendungen entstehen nicht durch mehr generierten Testcode, sondern durch eine wartbare Grundlage. Lilia Gargouri, die Testautomatisierung für große E-Government-Projekte aufbaut, nennt drei Bausteine: eine verlässliche Erkennung der UI-Elemente über ein eigenes HTML-Attribut für Tests, eine bewusst kleine Auswahl aussagekräftiger Testfälle und eine geschichtete Framework-Architektur mit zentraler Logik und einer festen Namenskonvention.
Das Wichtigste in Kürze
- Ein eigenes HTML-Attribut, das nur für Tests existiert und 2017 eingeführt wurde, sorgt in einem großen Portfolio von Behördenanwendungen bis heute für eine stabile Erkennung der UI-Elemente.
- Wer das DOM für das Testwerkzeug auf den gerade relevanten Abschnitt eingrenzt, trifft auch Felder, die sich auf einer Seite mehrfach wiederholen, ohne komplizierte Selektoren.
- Fünfzehn gut gewählte Testfälle für die wichtigsten Szenarien bringen auf Dauer mehr als fünfhundert unscharfe, die Laufzeit und Wartungskapazität auffressen.
- Fest eingebaute Wartezeiten summieren sich unbemerkt: In einem untersuchten Projekt kosteten sie zwei Stunden pro Testlauf, bis ein Detektor für den Belegt-Zustand der Anwendung sie ersetzte.
- Heißt jede Automatisierungsprozedur “Aktion plus fachliche Bezeichnung”, etwa “Name eingeben”, finden sich neue Teammitglieder ohne zusätzliche Dokumentation im Testcode zurecht.
Testautomatisierung ist Softwareentwicklung, keine Nebensache
Wer Ende-zu-Ende-Tests über Jahre stabil halten will, muss die Testautomatisierung als eigenes Softwareprojekt innerhalb des großen Projekts behandeln. Das heißt: Architektur, Namenskonventionen, Entwurfsmuster und dieselbe Sorgfalt wie beim Produktivcode.
Lilia Gargouri war fünfzehn Jahre in der Softwareentwicklung, bevor sie in die Qualitätssicherung und die Testautomatisierung im großen Stil wechselte. Aus dieser Sicht ist die Abkürzungsmentalität rund um Automatisierung die Wurzel der meisten Probleme. Schnell generierter Testcode skaliert nicht. Er beschleunigt nur das Chaos.
Was ein unzuverlässiger Ende-zu-Ende-Test ist
Ein unzuverlässiger Ende-zu-Ende-Test, im Jargon ein “flaky” Test, schlägt mal fehl und läuft mal durch, ohne dass sich an der Anwendung etwas geändert hat. Ende-zu-Ende-Tests stehen an der Spitze der Testpyramide, und genau dort sammelt sich diese Unzuverlässigkeit. Teams verbrauchen regelmäßig einen großen Teil ihrer Automatisierungszeit mit instabilen Tests und Wartung. Die Probleme sind alt und bekannt, und sie bleiben. Wer ohne Strategie einfach KI darauf ansetzt, vervielfacht sie nur schneller.
Ein typisches Beispiel ist eine Tabelle mit fünfzig Lösch-Buttons, jeder davon ein kleines Symbol. Der Test soll genau einen davon treffen. Ein wackeliger Locator erwischt heute den richtigen und morgen den falschen oder gar keinen. Das Ergebnis ist rot, obwohl die Anwendung funktioniert.
Warum große Unternehmensanwendungen schwache Automatisierung bestrafen
Langlebige Unternehmenssoftware legt jede Schwäche einer Testsuite offen. Läuft eine Anwendung fünfundzwanzig Jahre, entwickelt sie sich über viele Release-Zyklen weiter und ist fachlich komplex, dann wächst alles gleichzeitig: die Zahl der Tests, die Laufzeit und der Wartungsaufwand.
Lilia baut Automatisierung für große E-Government-Projekte, und dort ist dieser Druck ständig da. Neue Funktionen kommen dazu, während die bestehenden gepflegt werden müssen, und die Suite wächst in jede Richtung. Ohne klare Strategie von Anfang an landen Teams schnell in der Wartungsfalle und kommen nicht mehr heraus.
Deshalb zählt die Reihenfolge. Am Anfang steht nicht das Generieren von Tests. Zuerst kommt die Erkennung der Elemente, dann der Testentwurf, dann die Priorisierung und erst ganz am Schluss die Implementierung.
Wie ein eigenes HTML-Attribut die Oberfläche testbar macht
Zuverlässige Ende-zu-Ende-Automatisierung beginnt mit einer genauen Erkennung der Elemente, und die hängt an der Qualität des HTML. Die Erkennung im Nachhinein zu reparieren, ist ein Provisorium, keine Lösung.
Weltweit zielt der größte Teil der Automatisierung immer noch auf Weboberflächen. Die Schwierigkeit ist also, auf ein winziges, ganz bestimmtes Element zu zeigen. Genau hier scheitern instabile Locators.
Die dauerhafte Lösung ist ein eigenes HTML-Attribut, das nur für Tests existiert. Ob es “Data-Role-Attribut” heißt oder “Test-ID”, entscheidet das Team. Sein Wert dient ausschließlich der Erkennung im Test, er ist in der ganzen Anwendung Pflicht und ändert sich nie. Fehlt das Attribut, ist das ein Bug-Ticket für die Entwicklung.
Diese Entscheidung zahlt sich über Jahre aus. Lilias Team hat das Attribut 2017 eingeführt und profitiert bis heute davon. Automatisierung ist die Summe vieler kleiner Entscheidungen, die sich zu Effizienz aufaddieren.
Der zweite Baustein ist ein zentraler Mapper. Er ordnet jedem Attributwert eine Klasse der Testautomatisierung zu, sodass das Werkzeug eine Tabelle, eine Zeile, eine Zelle oder einen Symbol-Button erkennt. Liegt diese Zuordnung an einer Stelle, liegen dort auch Implementierung und Wartung, und sie ist geladen, sobald sich der Browser öffnet.
Barrierefreiheitsattribute als zusätzliche Informationsquelle
Barrierefreiheitsattribute liefern dem Testcode gleich noch Bedeutung mit. E-Government-Anwendungen müssen auch für blinde Menschen nutzbar sein, deshalb sind Attribute wie aria-label und alt ohnehin vorhanden und inhaltlich aussagekräftig.
Lilias Skripte lesen diese Informationen aus und reichern damit die Identität der UI-Elemente an. Der Nebeneffekt ist echte Überdeckung: Die Tests prüfen nebenbei, ob die Barrierefreiheitsattribute für die Menschen, die darauf angewiesen sind, überhaupt Sinn ergeben. Und Code, der sich liest wie die Oberfläche, die er bedient, versteht man später leichter.
Den Ausschnitt verkleinern, um genauer zu treffen
Wer das DOM auf einen einzelnen Abschnitt eingrenzt, kann präzise zielen. Wiederholt sich ein Feldname in vielen Abschnitten, trifft man das fünfte Feld auf einer vollen Seite nicht verlässlich.
Der Trick: Der Rest des DOM verschwindet für das Werkzeug, nur der relevante Abschnitt bleibt übrig. Mit kleinem Ausschnitt trifft der Test genau, die Läufe werden stabil, und auch Wiederholungsläufen kann man trauen. Stabilität entsteht aus vielen solchen Entscheidungen zusammen.
Über Labels identifizieren für stabilen, generischen Code
Die Identifizierung über Labels hält Tests lesbar und in diesem Umfeld auch stabil. In Behördenanwendungen ändern sich die Beschriftungen von Eingabefeldern selten, ein Locator wie “das Textfeld mit dem Label Name” hält also lange.
Labels machen außerdem Mehrsprachigkeit billig. Die Übersetzungen der Labels kommen in eine Tabelle, der Code verweist generisch auf das Label, und dieselbe Codezeile läuft je nach Anmeldung auf Englisch, Italienisch oder in jeder anderen Sprache. Eine ID, eine Zeile, keine Duplikate.
Wenige Testfälle mit hohem Wert entwerfen
Wenige, gut geschnittene Ende-zu-Ende-Tests schlagen eine große, redundante Suite. Von fünfhundert Testfällen hält Lilia wenig. Fünfzehn, die das wichtigste Verhalten abdecken, reichen, um ein ernsthaftes Gespräch über Qualität zu beginnen: Sind die grün, kann man über den Rest reden.
Jeder Testfall ist wie ein Stein im Rucksack, den du jahrelang mitträgst. Ist der Rucksack schwer, leidet die ganze Tour. Also entscheidest du bewusst, was einen Platz verdient.
Drei Säulen bestimmen die Qualität eines Testfalls.
| Säule | Leitfrage |
|---|---|
| Szenario | Worauf liegt der Fokus, und ist er kritisch? Lässt sich ein Schritt streichen, ohne Überdeckung zu verlieren? |
| Testdaten | Welche Grenzwerte und Äquivalenzklassen haben echten Wert, und sind die Daten wiederverwendbar und wartbar? |
| Implementierung | Hält die Implementierung den Wartungsaufwand niedrig, ob manuell oder automatisiert? |
Schneide jeden Testfall auf seinen Kern zurück. Zieh die Fälle nicht blind aus dem Testmanagementwerkzeug und automatisiere sie mitsamt ihrer Redundanz. Kläre den Fokus, streich Schritte, die nichts beitragen, und wähle Testdaten, die wirklich etwas abdecken, statt überall “ABC123” einzutragen. Teure Automatisierung mit bedeutungslosen Daten bringt nichts.
Erst das Backlog priorisieren, dann automatisieren
Ein fertig definiertes Backlog ist kein Startschuss fürs Programmieren. Es ist der Moment, in dem du eine Reihenfolge wählst, die zu deiner Lage passt.
Prioritäten hängen von Strategie und Kontext ab. Vielleicht automatisierst du zuerst die geschäftskritischen Fälle, damit eine grüne Pipeline dort Sicherheit gibt, wo es darauf ankommt. Vielleicht nimmst du dir die Fälle vor, die manuelle Tester am meisten Zeit kosten, damit sie sich um neue Funktionen kümmern können. Vielleicht deckst du zuerst die Happy Paths oder die meistgenutzten Abläufe ab. Die richtige Reihenfolge ergibt sich aus dem Hier und Jetzt, nicht aus einer festen Regel.
Ein dreischichtiges Framework hält Ende-zu-Ende-Tests wartbar
Eine geschichtete Architektur sorgt dafür, dass die Automatisierung Jahre voller Änderungen übersteht. Die Struktur folgt dem Automatisierungsmodell des ISTQB Advanced Level: Kernbibliotheken unten, Geschäftslogik in der Mitte, Testskripte oben.
Testfälle und Testsuites liegen ganz oben und rufen Prozeduren auf, die die fachlichen Abläufe abbilden. Die Geschäftslogik ruft die Bibliotheken auf. Jede Schicht hat genau eine Aufgabe.
Auch die Bibliotheken sind geschichtet. Das Werkzeug bringt eine Standardbibliothek mit, und die reicht nie. Darüber liegt eine projektübergreifende Firmenbibliothek für Funktionen wie das Wechseln zwischen Browserfenstern, damit nicht jedes Projekt sie neu erfindet. Darüber folgt eine Projektbibliothek für wiederkehrende Interaktionen, etwa ein Kontextmenü hinter drei Punkten: Eine Prozedur bekommt die gewünschte Aktion und führt sie aus. Spezialbibliotheken kümmern sich um E-Mail- und PDF-Inhalte. Jedes Mal, wenn du etwas Neues baust, gehört es in die passende Bibliothek.
Eine Namenskonvention sorgt für sauberen Code
Einheitliche Namen halten eine wachsende Suite lesbar. Welche Konvention es genau ist, zählt weniger als die Konsequenz, mit der man sie überall und immer anwendet.
Lilias Konvention lautet: Aktion plus Fachbegriff. Die Aktion ist “eingeben”, “markieren” oder “klicken”, der Fachbegriff ist das Label. “Name eingeben” heißt also, einen Wert in das Feld mit dem Label “Name” zu schreiben. Der technische Widget-Typ taucht im Namen nicht auf: Checkbox, Radiobutton und Datumsauswahl sind alle “eingeben” plus ihr Label. Man könnte die Augen schließen und sich allein anhand der Fachbegriffe durch die Anwendung bewegen.
Lesbarer Code verkürzt die Einarbeitung deutlich. Neue Leute in Lilias Team verbringen bewusst Wochen mit einem einzigen Testfall, bis sie die Konvention verinnerlicht haben und überall anwenden. Die Struktur der Automatisierung entspricht der Struktur der Oberfläche. Wer sich in der Oberfläche auskennt, findet sich auch im Code zurecht.
Darin steckt auch ein Warnsignal. Wenn du dich dabei ertappst, dass du suchst, wo etwas implementiert ist, ist deine Ordnung nicht gut genug.
“Wenn du dich dabei ertappst, dass du etwas suchst, wo haben wir das implementiert und wo, dann ist dein System nicht gut genug.”
(Lilia Gargouri)
Wie man der Wartungsfalle entkommt: eine Änderung, eine Stelle
Zentralisierung und generischer Code halten die Wartungskosten bei Änderungen klein. Ändert sich etwas, gibt es in einer gut strukturierten Suite im Idealfall genau eine Stelle, an der du es anpasst.
Zum Vergleich: verkettete IDs und roher XPath. Schlägt so eine Zeile fehl, zerlegst du sie erst, um den kaputten Teil zu finden, dann entscheiden, ob es ein Bug oder ein Feature ist, und das jedes Mal aufs Neue, wenn die Zeile fehlschlägt. Unter Release-Druck verlieren Teams genau damit ihre Tage.
Gefährlich wird es, wenn die Suite ohne Struktur wächst. Du suchst nach einer ID und findest fünfhundert Treffer, dann steht ein Release-Kandidat an, in dem sich genau dieses Element als Feature geändert hat, und du musst fünfhundert Stellen schnell reparieren. Das ist eine tickende Zeitbombe.
Stabile Testläufe statt verschwendeter Wartezeit
Stabile Ausführung entsteht, wenn der Test auf das richtige Signal wartet und nicht auf die Uhr. Fest eingebaute Wartezeiten summieren sich unbemerkt und lösen an der Wurzel nichts.
Statt fester Wartezeiten hilft ein Detektor, der erkennt, ob die Anwendung beschäftigt ist. Er baut auf demselben Resolver auf, wartet, solange der Spinner sichtbar ist, und macht weiter, sobald die Anwendung bereit ist. In einem Projekt mit vierzig Testsuites kamen allein durch Wartezeiten zwei Stunden pro Lauf zusammen: zwei Millisekunden hier, zwei Millisekunden da, für nichts verloren.
Halte die Umgebung aktuell, denn Versionen beeinflussen sich gegenseitig. Browser, Java, Gradle, das Testobjekt und das Testwerkzeug verändern sich mit der Zeit und müssen zusammenpassen, damit alles stabil bleibt.
Isoliere den Testlauf. Auf der Maschine oder im Container sollte nichts anderes parallel laufen, sonst erbst du Nebeneffekte, Schwankungen in der Performance und Fehler, die nicht deine sind. Und kein anderer Prozess sollte an die Daten deiner Tests gehen, sonst jagst du wegen fremder Exceptions Phantomfehlern hinterher.
Modulare Testfälle schaffen Spielraum unter Druck
Modularität macht aus einer starren Suite etwas, das du bei Bedarf neu zusammenstellen kannst. Jeder Testfall ist eine eigenständige Einheit, der egal ist, was vor oder nach ihr läuft.
So lassen sich Testläufe aus einer Auswirkungsanalyse zusammenstellen: Du wählst die nötigen Themen und lässt sie gemeinsam laufen. Die Testsuites sind nach fachlichen Themen getrennt. Wächst eine über dein Zeitlimit hinaus, bei Lilia ist das eine Stunde, teilst du sie ohne großen Aufwand in Unterthemen auf. So kannst du Smoke-, Integrations- und funktionale Tests nacheinander laufen lassen und früh abbrechen, wenn schon die kritische Ebene scheitert.
Der Nutzen zeigt sich in unangenehmen Momenten. Als ein Werkzeug-Update die Electron-Variante einer Fachanwendung lahmlegte, lief derselbe Testcode weiter gegen die Webversion. Geändert hat sich nur die Vorbedingung: Statt der Electron-App öffnete sich ein Browser. Nach fünf Minuten lagen funktionale Ergebnisse aus den Webtests vor, während das Electron-Problem behoben wurde, und das Release war nicht blockiert.
Wie man eine alte, instabile Testsuite rettet
Die Rettung einer Altsuite beginnt mit einem parallelen Repository, nicht mit einem Umbau an Ort und Stelle. Die alte Welt läuft weiter, daneben entsteht die neue, und irgendwann schaltest du komplett um.
Zuerst steht die saubere Struktur, aufgesetzt aus einer Projektvorlage. Darin implementierst du neue Testfälle nach der Namenskonvention. Brauchst du Prozeduren und Bibliotheken, holst du die wertvollen Teile einzeln aus der alten Suite und baust sie als sauberen Code in der neuen Bibliothek nach. Lilia hat genau diese Situation als Entwicklerin übernommen und die neue Lösung Stück für Stück aus dem alten Durcheinander herausgelöst.
Die Migration braucht Zeit, und anzufangen lohnt sich trotzdem. Auch zehn Kilometer beginnen mit dem ersten Schritt, und die Alternative ist ein weiterer Tag voller instabiler Tests und ein großer Teil der Arbeitszeit, der in Wartung versickert. Weniger Wartung ist am Ende eine Frage der Lebensqualität.
Häufig gestellte Fragen
Warum werden Ende-zu-Ende-Tests in großen, langlebigen Anwendungen unzuverlässig?
Ende-zu-Ende-Tests stehen an der Spitze der Testpyramide, und genau dort konzentrieren sich die Unzuverlässigkeiten. Bei Unternehmenssoftware, die 25 Jahre lang läuft, wächst alles gleichzeitig: die Anzahl der Tests, die Ausführungszeit und der Aufwand für die Wartung. Teams, die damit beginnen, Testcode zu generieren, ohne zuerst die Erkennung und das Design zu klären, schaffen es nicht, die Testsuite skalierbar zu machen. Sie beschleunigen das Chaos.
Was macht einen UI-Locator über viele Jahre hinweg stabil?
Ein spezielles HTML-Attribut, das ausschließlich zum Testen hinzugefügt wurde. Sein Wert dient nur der Testerkennung, ist in der gesamten Anwendung eine Anforderung und ändert sich nie; fehlt es, ist das ein Bug-Ticket für den Entwickler. Das Team von Lilia Gargouri hat ein solches Attribut 2017 eingeführt und profitiert noch immer davon. Ein zentraler Mapper verknüpft jeden Wert mit einer Klasse für die Testautomatisierung.
Können Barrierefreiheitsattribute für die Testautomatisierung genutzt werden?
Ja. In E-Government-Anwendungen müssen Attribute wie „aria-label“ und „alt“ für blinde Nutzer ohnehin vorhanden sein, und sie haben eine echte Bedeutung. Testskripte extrahieren diese Informationen, um die Identität von UI-Elementen anzureichern. Der Nebeneffekt ist die Überdeckung: Die Tests prüfen implizit, ob die Barrierefreiheitsattribute für die Menschen, die darauf angewiesen sind, Sinn ergeben.
Wie können dieselben automatisierten Tests für mehrere Sprachen ausgeführt werden?
Indem Felder anhand ihrer sichtbaren Beschriftung statt anhand technischer IDs identifiziert werden. Die Übersetzungen der Beschriftungen liegen in einer Tabelle vor, der Testcode verweist generisch auf die Beschriftung, und dieselbe Zeile wird je nach Anmeldung für Englisch, Italienisch oder eine andere Sprache ausgeführt. Eine ID, eine Zeile, keine doppelten Testfälle pro Sprache. Bei Behördenanwendungen ändern sich die Beschriftungen von Eingabefeldern selten, sodass solche Locators zuverlässig funktionieren.
Ist eine große Anzahl automatisierter Ende-zu-Ende-Tests ein gutes Zeichen?
Nein. Fünfzehn Testfälle, die die wichtigsten Verhaltensweisen abdecken, liefern einen nachhaltigeren Nutzen als fünfhundert vage definierte, die die Ausführungszeit und die Wartungskapazität belasten. Jeder Fall ist ein Stein im Rucksack, den man jahrelang mit sich herumträgt. Drei Säulen bestimmen die Qualität: der Fokus auf das Szenario, Testdaten, die echte Grenzen abdecken statt „ABC123“, und eine Implementierung, die den Wartungsaufwand gering hält.
Warum sind fest programmierte Wartezeiten ein Problem bei automatisierten Testläufen?
Sie häufen sich unbemerkt an und lösen das Problem nicht an der Wurzel. In einem Projekt summierten sich die Wartezeiten über vierzig Testsuiten hinweg auf zwei Stunden pro Durchlauf, zwei Millisekunden hier und zwei Millisekunden dort. Die Alternative ist ein „Application Busy Detector“, der auf demselben Resolver basiert: Er wartet, solange der Spinner sichtbar ist, und fährt fort, sobald die Anwendung bereit ist.
Wie wird Testcode für neue Teammitglieder lesbar genug?
Durch eine einheitliche Namenskonvention, die überall angewendet wird. Jede Prozedur wird als „Aktion“ plus „Geschäftsbezeichnung“ benannt, zum Beispiel „Name eingeben“, während der technische Widget-Typ aus der Bezeichnung herausgehalten wird: Checkbox, Radiobutton und Datumsauswahl heißen alle „eingeben“ plus ihre jeweilige Bezeichnung. Jeder, der sich in der Benutzeroberfläche zurechtfindet, kann sich dann auch im Code zurechtfinden, ganz ohne separate Dokumentation.
Was bringt es, wenn Testfälle unabhängig voneinander laufen?
Du kannst Testläufe nach Bedarf neu zusammenstellen, zum Beispiel ausgehend von einer Auswirkungsanalyse, und eine Testsuite in Unterthemen aufteilen, wenn sie dein Zeitlimit überschreitet (in Lilias Setup ist das eine Stunde). Der Nutzen zeigt sich in heiklen Situationen: Als ein Tool-Update die Electron-Variante einer Anwendung lahmlegte, lief derselbe Test nach Änderung nur der Vorbedingung auf der Webversion, und die Veröffentlichung wurde nicht blockiert.


