14.09.2021 von Michael Geers

Die Testpyramide wird als Metapher eingesetzt, um verschiedene Arten von Tests beim Entwickeln von (Web-)Anwendungen einzuordnen. Was bringt es, die Testpyramide mal auf den Kopf zu drehen?

Wer sich mit dem Thema Testen von (Web-)Anwendungen beschäftigt, stößt früher oder später auf die Testpyramide. Die Testpyramide ist eine Metapher zur Kategorisierung verschiedener Arten von Tests. Wir haben in einem unserer Teams die Pyramide auf den Kopf gestellt. Welche Motivation dahinter steht und was es bringt, soll dieser Artikel klären.

Klassische Testpyramide und umgedrehte Testpyramide

Welche Tests gibt es überhaupt?

Es gibt immer wieder leicht abweichende Bezeichnungen der verschiedenen Schichten der Pyramide. Die Spitze bilden mal UI-Tests, mal Ende-zu-Ende-Tests. Manchmal wird die Mitte mit Service-Tests beschrieben, manchmal stehen hier Integrationstests. Die Basis bilden in der Regel Unit-Tests. Aber auch hier kursieren unterschiedliche Begriffe. Weil diese Begriffe auch durchaus unterschiedliche Bedeutungen haben (ein UI-Test kann durchaus ein Unit-Test sein), schärfen wir zunächst die Begriffe, die in diesem Artikel Verwendung finden.

Unit-Tests

Unit-Tests überprüfen die Funktionalität einer Komponente. Eine Komponente entspricht dabei in der objektorientierten Programmierung üblicherweise einer Klasse. Eventuelle externe Abhängigkeiten (andere Klassen) werden gemockt. Ihr Verhalten wird simuliert, sie sollen nicht mit getestet werden. Auch im Frontend kann eine isolierte Javascript-Komponente mit einem Unit-Test versehen werden.

Integrationstests

Integrationstests überprüfen das Zusammenspiel mehrerer Komponenten miteinander. Nach dieser Definition wäre ein Test, der das Zusammenspiel zweier Klassen abdeckt, ein Integrationstest. Tatsächlich geht es in der Praxis um das gemeinsame Funktionieren mehrerer Klassen, oft sogar in Verbindung mit einer Datenbank. In einer engeren Definition sind Integrationstests solche Tests, die einen HTTP-Endpunkt aufrufen und bis zur Datenbank hinunterreichen. Im Falle einer HTTP-Schnittstelle würde also eine Anfrage an eine bestimmte Route gesendet und die Antwort (Statuscode & Body) überprüft. So verstehen wir Integrationstests für Webanwendungen.

Akzeptanztests

UI-Test, Ende-zu-Ende-Test, Klickstreckentest: Viele Begriffe, die nicht unbedingt ganz dasselbe meinen. Wir sprechen deshalb von Akzeptanztests. Dieser Begriff soll zum Ausdruck bringen, dass hier fachliche Akzeptanzkriterien überprüft werden. Akzeptanztests sind dabei immer Ende-zu-Ende-Tests, indem sie UI, Backend und Datenhaltung mit einbeziehen. Durch Akzeptanztests wird geprüft, dass die Anwendung genau das tut, was Nutzer:innen von ihr erwarten.

Akzeptanztests: Teuer und langsam?

Mit der Einordnung der verschiedenen Testarten in die Pyramide geht eine Bewertung einher. Tests an der Spitze der Pyramide seien demnach regelmäßig teuer in der Erstellung und langsam in der Ausführung. Je weiter nach unten wir kommen, umso billiger und schneller werden sie. Als Folge wird dann auch immer empfohlen, eine möglichst umfangreiche Basis an Unit-Tests zu erstellen und sich bei den Akzeptanztests auf wenige, aussagekräftige Fälle zu beschränken.

Testpyramide mit gängiger Bewertung

Diese gängige Bewertung lässt wichtige andere Kriterien außer Acht. Wie ist zum Beispiel der Wert verschiedener Tests für die Qualität einer Anwendung zu bewerten? Oder wie aussagekräftig sind sie?

Ein Akzeptanztest prüft eine bestimmte Funktionalität der Anwendung in genau der Weise, wie sie durch die Product Owner gewünscht wird. Er berücksichtigt die konkrete Umsetzung durch das Entwicklungsteam. Die Perspektive des Tests ist immer die der Nutzer:innen. Ein solcher Test hat besondere Qualitäten.

Er stellt natürlich sicher, dass die Anwendung wie erwartet funktioniert. Genauso stärkt er aber auch das Vertrauen im Team. Vertrauen darin, dass die Anwendung das tut, wofür sie entwickelt wurde. Vertrauen darin, gut vor Regression geschützt zu sein. Aber auch das Vertrauen zwischen Product Owner und Entwicklungsteam wächst durch Akzeptanztests, weil alle sich gemeinsam darauf verlassen können, dass fachliche Anforderungen erfüllt sind. Eine Menge guter Akzeptanztests bilden außerdem die Basis für Continuous Deployment.

Oft zitiert wird der dokumentarische Charakter von Tests. Ein Test, der einmal geschrieben wurde, hält das gewünschte Verhalten in schriftlicher Form fest. Das gilt für alle oben beschriebenen Testarten. Die meiste Aussagekraft besitzt diese Eigenschaft aber auf Ebene der Akzeptanztests. Ein Test, der prüft, dass beispielsweise nach Anwendung eines 5%-Gutscheins die Warenkorbsumme um 5% reduziert ist, hat eine stärkere Aussage als einer, der prüft, dass die Prozentrechnung im Backend auf Klassenebene richtig funktioniert. Das bedeutet nicht, dass ein Unit-Test für die Prozentrechnung keine Daseinsberechtigung hätte. Er kann beispielsweise viel besser Edge-Cases abbilden. Für die Dokumentation, was ein 5%-Gutschein bewirkt, ist der Akzeptanztest aber besser geeignet.

Testpyramide mit weiteren Bewertungskriterien

In Zeiten von modernen Test-Frameworks und Cloud-Computing ist außerdem die Bewertung "teuer und langsam" zumindest kritisch zu betrachten. Cypress beispielsweise erlaubt eine schnelle und einfache Formulierung von Testfällen. Zudem nutzt es die Automatisierungsfähigkeiten aktueller Browser direkt und kommt somit ohne mächtige Abstraktionsschichten (wie z.B. bei Selenium) aus. Dies führt zu kürzeren Laufzeiten und zu robusteren und zuverlässigeren Tests. Im Rahmen von Pipelines auf CI-Servern, die auf dynamisch skalierbaren Instanzen in der Cloud ausgeführt werden, laufen Akzeptanztests flott. Sie dringen nicht in den Millisekundenbereich vor, der für Unit-Tests typisch ist. Dennoch ist es möglich, hunderte Testfälle in wenigen Minuten zu durchlaufen.

Ein typischer Akzeptanztest in Cypress

Fokus auf die Fachlichkeit

Für ein voll automatisiertes Continuous Deployment haben Akzeptanztests damit unschlagbare Qualitäten. Sie sichern das Funktionieren der Anwendung aus fachlicher Sicht und schaffen Vertrauen, dass nach dem Deployment die Anwendung weiterhin genau das macht, was sie soll. Dazu lassen sich Akzeptanztests heute einfach aufsetzen und ausführen. Warum also nicht einfach die Pyramide auf den Kopf stellen?

Umgedrehte Testpyramide

Genau dafür haben wir uns im letzten Projekt sehr früh und ganz bewusst entschieden. Wir haben einen unbedingten Fokus auf die Akzeptanztests gelegt. Dafür schreibt unser Product Owner User Stories mit Akzeptanzkriterien, die sich in den meisten Fällen eins zu eins als Überschriften für Testszenarien übernehmen lassen. Sowohl Product Owner als auch Entwicklungsteam sind sich dadurch sicher: Die Anwendung tut, was sie soll. Wenn mal ein Test fehlschlägt, ist dies mit sehr hoher Wahrscheinlichkeit ein Zeichen, dass tatsächlich etwas kaputt ist. Wir müssen nach einer fachlich gewünschten Änderung nicht mehr zig Unit-Tests anpassen, weil diese der neuen Logik nicht mehr entsprechen. Wir testen nur noch, was wirklich wichtig ist.

Das heißt nicht, dass es keine Integrations- oder Unit-Tests mehr gäbe. Die haben weiterhin ihren Wert und ihre Daseinsberechtigung. Komplexere Preisberechnungen lassen sich zum Beispiel hervorragend durch Unit-Tests abdecken. Auch gibt es APIs, die keine direkte Entsprechung im UI haben und deshalb durch einen Integrationstest abgesichert werden. Die Akzeptanztests sind uns bloß wichtiger und wir haben mehr davon.

Anzahl und Dauer verschiedener Tests in einer Build-Pipeline

Durch den Fokus auf Akzeptanztests haben wir heute eine hohe Sicherheit beim voll automatisierten Deployment bis in Produktion. Das ganze Team vertraut darauf, dass die Anwendung richtig funktioniert. Die Qualität unserer Software wird besser.