Die Test(automations)pyramide: ein einfaches Gebilde voller Missverständnisse
von Klemens Loschy
Die Testautomationspyramide ist wohl jedem in der Branche ein Begriff: Das Ziel ist eine einfach verständliche Darstellung, wie man den Test-Fokus in einem Software-Projekt prinzipiell gestalten sollte. Die einfachste Darstellung ist die Pyramide mit 3 Ebenen, doch bereits bei den einfachsten Abbildungen gibt es unterschiedliche Ausprägungen und (missverständlich) verwendete Begrifflichkeiten:
Abbildung 1: (Quelle: anymindgroup.com/news/tech-blog/15053/)
Abbildung 2: Die Testpyramide von Mike Cohn (Quelle: www.openknowledge.de/blog/die-testpyramide)
Abbildung 3: (Quelle: betterprogramming.pub/the-test-pyramid-80d77535573)
Sind „System-Tests“ und „E2E“ Tests eigentlich dasselbe? Genau genommen sind sie das nicht (Quelle ISTQB), auch wenn das in der Praxis weniger unterschieden wird. „UI“ beschreibt dann eine Interaktionsmöglichkeit und weniger einen Umfang oder Scope. Und trotzdem werden diese unterschiedlichen Begriffe oft gleichbedeutend verwendet. Im Laufe der Zeit haben sich davon etliche Abwandlungen und Erweiterungen gebildet: Die traditionellen 3 Ebenen wurden zum Teil unterteilt (Integration wurde z.B. zu API, Integration und Component) oder durch zusätzliche Ebenen erweitert oder ein Wölkchen auf der Spitze platziert und damit eigentlich eine „Testpyramide“ geschaffen (die Wolke steht für manuelle Tests).
Abbildung 4: (Quelle: de.parasoft.com/blog/how-to-enable-quality-at-speed-in-5-steps/)
Abbildung 5: (Quelle: www.browserstack.com/guide/testing-pyramid-for-test-automation)
Eine weitere Darstellung ist die 3-dimensionale Pyramide („extended test pyramid“), die zusätzlichen Informationen zu den einzelnen Ebenen bieten möchte, wie z.B. welche Non Functional Requirements in den einzelnen Ebenen fokussiert werden sollten, in welcher Testumgebung die Tests der jeweiligen Ebene durchgeführt werden sollten oder wer für Testfälle verantwortlich ist.
Abbildung 6: Erweiterung um zwei Dimensionen mit zusätzlichem Informationsgehalt (Quelle: leaddev.com/agile-other-ways-working/demystifying-software-engineering-test-pyramid)
Wieso eigentlich eine Pyramide?
Die Pyramidenform ist natürlich kein Zufall und steht für „unten ist irgendetwas mehr als oben“ – also sinngemäß, denn zum Teil muss man schon sehr kreativ sein, um das Pattern im Satzbau immer einzuhalten.
Von was genau es „mehr“ gibt, hat wieder viele Ausprägungen:
- Die Anzahl der Testfälle unten ist höher als oben
- Die Durchlaufzeit der Testfälle (gesamt) ist unten geringer als oben („mehr schnell“ als oben hört sich dann doch komisch an) („Immediate Feedback“ als Stichwort)
- Der Aufwand, Testfälle zu erstellen, ist unten geringer als oben
- Die Stabilität der Testfälle ist unten höher als oben (mit dem Wartungsaufwand verhält es sich dann genau umgekehrt)
- …
Damit ergibt sich auch eine weitere Aussage, die sich aus der Form der Pyramide ergibt: Die unteren, breiteren Ebenen sind enorm wichtig für die Stabilität der Pyramide! Legt man zu wenig Wert auf die s.g. „Foundation“ (Deutsch: Basis, Grundlage oder Fundament), beginnt die Pyramide zu wackeln oder bricht in sich zusammen. Das ist natürlich wieder eine Metapher für die Qualität im Software-Projekt.
Wieso bilden Unit-Tests das Fundament?
Unit Tests haben einige wesentlichen Eigenschaften, die sie für das Fundament eines Software-Projekts unersetzbar machen:
- Stabilität: Ein Unit-Test (vorausgesetzt, er ist richtig geschrieben), ist stabil – Punkt. Ein Test über die UI kann noch so „richtig“ geschrieben sein und wird trotzdem niemals die Stabilität eines Unit-Tests erreichen: Die Einflussfaktoren auf einen Test über die UI sind einfach enorm und jede kleine Abweichung kann die erfolgreiche Durchführung verhindern.
- Durchlaufzeit: Die Abarbeitung von Code ist einfach schnell, viel schneller als Tests über externe Schnittstellen oder gar die UI jemals sein könnten.
- Einfach komplexe Szenarien testen: Eine Grundvoraussetzung für Unit-Tests ist der Einsatz von Mocking-Frameworks. Darüber selbst kann man lange Artikel schreiben, deswegen nur kurz: Mit Mocking-Frameworks ersetzt man Abhängigkeiten durch s.g. Mocks, also Platzhalter, die auf bestimmte Anfragen mit vordefinierten Antworten reagieren. Damit ist es möglich, die zu testende Unit in den unterschiedlichsten Ausprägungen zu testen, die ohne Mocking nur sehr schwer und mit viel Aufwand herzustellen wären.
- Besseres Software-Design: Wenn man sich beim Unit-Test Schreiben buchstäblich die Finger bricht und Kopfschmerzen bekommt, ist die Ursache meist eine schlechte Architektur (der zu testenden Units) und sollte als wichtiger Trigger für ein Design Review dienen. Dem kann man mit Test-Driven-Development bereits von Beginn an aktiv vorbeugen.
- …
Die Liste kann man problemlos mit weiteren Gründen weiterführen, wieso Unit-Tests zu Recht die Basis einer guten und effizienten Testautomationsstrategie sein müssen.
Wieso dann nicht nur Unit-Tests?
Trotz der vielen Vorteile und positiven Eigenschaften von Unit-Tests reichen sie für sich allein nicht aus. Es ist zwingend notwendig (vorausgesetzt natürlich die Qualität ist wichtig, aber davon gehe ich aus, wenn Sie diesen Artikel lesen), die oberen Ebenen der Pyramide ebenfalls zu berücksichtigen. Ein System besteht neunmal aus mehreren Teilen (Komponenten, Schichten oder Systemen), die irgendwann miteinander über Schnittstellen kommunizieren müssen. Und natürlich ist die UI als Interaktionsschicht für den Endbenutzer enorm wichtig und muss dementsprechend qualitätsgesichert werden.
Aber wenn man UI-Tests sowieso machen sollte, dann reicht das doch theoretisch aus, denn nichts ist realer am produktiven Einsatz und näher am Endbenutzer als die UI, oder?
Ein gängiges Anti Pattern: Ice Cream Cone
Theoretisch lässt sich allein mittels Testfälle über die UI dieselbe Abdeckung erreichen, wie mit der Kombination aus allen 3 Ebenen der Testautomationspyramide (wenn wir davon ausgehen, dass über die UI alle Funktionen zur Verfügung stehen).
Abbildung 7: Das gängigste Anti Pattern: Ice Cream Cone (Quelle: saeedgatson.com/the-software-testing-ice-cream-cone/)
In der Theorie hat sich daraus das Anti Pattern namens „Ice Cream Cone“ (in Österreich würden wir dazu „Stanitzel“ sagen, für unsere Deutschen Kollegen müsste „Eiswaffel“ passen) entwickelt: Die Testautomationspyramide steht auf dem Kopf, der Fokus liegt auf der Testautomation über die UI und ist garniert mit einer großen Anzahl an manuellen Tests. Dieses Anti Pattern ist in vielen Software-Projekten trauriger Alltag, meistens fehlen dann die unteren Ebenen „Unit“ und „Integration“ gleich zur Gänze, die so wichtige Foundation ist also gar nicht vorhanden. Auch wenn das aus Abdeckungssicht wie erwähnt an sich möglich ist, gehen dabei die Vorteile der unteren Ebenen gänzlich verloren (Stabilität, Wartungsaufwand, Durchlaufzeit, …), die Pyramide wackelt, die Qualität des Software-Projekts ist nachhaltig in Gefahr.
Die Ursachen, wieso es in der Praxis immer wieder zu diesem Effekt kommt, sind einfach: Entwickler wollen nicht testen und Tester können nicht entwickeln (etwas überspitzt formuliert natürlich) und es gibt niemanden der dieses Gefüge versucht aufzubrechen. Die Tester versuchen dann mit den üblichen Testautomationswerkzeugen alle Anforderungen automatisiert abzudecken. Wenn das aus Zeitmangel nicht mehr funktioniert, steigt die Anzahl an manuellen Testfällen. Neue Funktionalitäten brauchen mehr Zeit im Test, Regressionstests dauern immer länger oder der Umfang wird gekürzt, Fehler häufen sich.
Ein neues Anti Pattern entsteht: Die Testautomation Cloud
Auch wenn der „Ice Cream Cone“ immer noch häufig anzutreffen ist, gibt es immer mehr Software-Projekte, die versuchen die Testautomationspyramide zu berücksichtigen. Ein wichtiger Aspekt, den die Testautomationspyramide aber nicht beschreibt, ist die inhaltliche Dimension der Testfälle: Die Ebenen existieren nicht lose nebeneinander, sondern müssen inhaltlich abgestimmt sein. Ziel muss es sein, Testinhalte in den oberen Ebenen einsparen zu können, weil sie in den unteren Ebenen bereits hinreichend abgedeckt sind, oder bewusst sehr wichtige Anforderungen auf mehreren Ebenen abzudecken.
Ein einfaches Beispiel: Das Passwortfeld soll prüfen, ob das neue Passwort allen Regeln entspricht. Sinnvoll ist es, auf Unit-Test Ebene alle Regeln zu testen und über die UI nur noch stellvertretend einen Fehlerfall, und natürlich den Gutfall mit einem regelkonformen Passwort.
Obwohl das eben ein sehr einfaches Beispiel ist, wird eines schnell klar: es geht nicht ohne Kommunikation. Nur wenn klar ist, welche Anforderungen in welcher Ebene abgedeckt sind, kann man diese Synergien nutzen und auf oberen Ebenen bestimmte Testfälle weglassen. Das hört sich jetzt nach „no na“ an, aber oft sind Entwickler und Tester immer noch organisatorisch und räumlich voneinander getrennt, eine Kommunikation zwischen diesen beiden Teams passiert also oft nicht einfach so, sondern muss gefordert und gefördert werden. Fehlt diese Kommunikation werden im best case dieselben Testfälle auf verschiedenen Ebenen umgesetzt, im worst case verlässt sich die obere Ebene auf die untere und gefährliche Testlücken entstehen. Die einzelnen Ebenen sind nicht mehr aufeinander aufbauend, sondern fliegen lose herum, und überschneiden sich noch durch Zufall: das Anti Pattern „Testautomation Cloud“ (© Klemens Loschy)
Abbildung 8: Das neue Anti Pattern, wenn der Ice Cream Cone erfolgreich beseitigt, wurde: Die Testautomation Cloud (Quelle: SEQIS GmbH)
Auch wenn eine funktionierende Kommunikation das A und O ist, ohne die nichts funktioniert, ist der nächste Schritt die toolunterstützte Anforderungsabdeckung. Tools wie z.B. Xray (ein im Test-Bereich weit verbreitetes Jira Plugin) helfen den Überblick zu bewahren, welche Anforderungen durch welche Tests abgedeckt sind. Die Integration von Xray mit Unit-Test Frameworks, Testautomationstframeworks und -tools ist möglich und konnten wir in einigen Projekt bereits erfolgreich umsetzen. Dadurch wird die Abdeckung automatisch bei der Testdurchführung aktualisiert und die manuelle Wartung entfällt komplett, was gerade bei mehreren 100 Unit-Tests auch nicht mehr manuell möglich wäre.
A fool with a tool is still a fool
Das Pattern der Testautomationspyramide ist nichts anderes als ein weiteres Tool im Toolkit eines Software-Projektes. Und wie jedes Tool ist, der richtige Einsatz maßgeblich für den Erfolg verantwortlich. Eine besondere Herausforderung ist, dass das Pattern überhaupt nur dann funktionieren kann, wenn die Kommunikation aller Beteiligten gegeben ist und über alle Fachkompetenzen hinweg Vertrauen herrscht. Wir verlassen uns im Projektalltag meist auf formale Prozesse, strenge Regeln und klobige Tools und vergessen darauf, dass sich alles um die Menschen dreht und wir viel mehr darauf achten müssen, dass wir ein Arbeitsumfeld schaffen, das das Miteinander fördert und die Kompetenzen stärkt. Mit einem gut eingespielten Team sind formale Prozesse obsolet, das wird einfach funktionieren. Umgekehrt rettet kein Prozess der Welt eine Sammlung loser Individuen.