Blog

(Acceptance) Test-Driven Development: Eine Einführung

JAN 30, 2019

Test-Driven Development (TDD) ist den meisten Entwicklern bekannt. Acceptance Test-Driven Development (ATDD) konzentriert sich stärker auf die geschäftlichen Anforderungen im Prozess und ist möglicherweise weniger vertraut. Beide Techniken ermöglichen kürzere Entwicklungszyklen. Diese praxisnahe Einführung zeigt euch, warum und wie.

Tatu Kairi

Principal Consultant

Tatu enjoys piña coladas, getting caught in the rain, is not into yoga and has half a brain.

Als jemand, der schon länger im DevOps-Bereich arbeitet, sind es die Transformationsreisen, die ich miterlebt habe, die diesen Job für mich lohnenswert machen.

Ich habe gesehen, wie die Umstellung auf kollaborativere Arbeitsweisen und der Einsatz interdisziplinärer Praktiken Hand in Hand gehen: Entwickler können ihre Fähigkeiten erweitern und vielseitiger werden. Letztlich fördert das ein besseres Verständnis zwischen spezialisierten Disziplinen, sodass das Endziel – ein zufriedener Kunde – besser und schneller erreicht werden kann.

Test-Driven Development (TDD) ist eine grundlegende Technik, die die meisten Entwickler einsetzen. Acceptance Test-Driven Development (ATDD) ist dagegen stärker auf die fachlichen Anforderungen im Prozess ausgerichtet und daher möglicherweise weniger bekannt. Beide Techniken ermöglichen jedoch kürzere Entwicklungszyklen und rücken die Bedürfnisse des Kunden in den Mittelpunkt der Projektarbeit.

Obwohl TDD und ATDD in der Branche weit verbreitet sind, werden beide Techniken nicht voll ausgeschöpft. Hier zeige ich euch, wie ihr ungenutzte Möglichkeiten erschließen könnt.

Zurück zu den Grundlagen: Shifting left

Jede Software durchläuft während ihres Lebenszyklus die folgenden Phasen:

the waterfall lifecycle of software

Zunächst hat jemand eine Idee, die ein Problem löst oder etwas ermöglicht, das zuvor außer Reichweite lag. Daraus ergeben sich bestimmte Anforderungen, die anschließend – technisch und finanziell – geplant werden, bevor sie umgesetzt werden. Danach wird die Qualität der Lösung bewertet. Wir müssen prüfen, ob die Software technisch wie vorgesehen funktioniert, und validieren, ob sie ihre Spezifikation erfüllt. Schließlich muss die Software so lange gewartet werden, bis sie außer Betrieb genommen wird.

Nicht vergessen: Diese Phasen sind unvermeidlich. Mit anderen Worten: Die Softwareentwicklung kann keine dieser Phasen überspringen – jede muss irgendwann berücksichtigt werden. Fehlende Anforderungen oder ausgesparte Wartung bedeuten lediglich, dass ihr die jeweilige Phase sehr schlecht behandelt habt – aber behandelt habt ihr sie trotzdem.

Das Ziel von Agile und DevOps ist nicht, Arbeit zu umgehen, sondern Arbeit durch intelligente Arbeitsweisen und Automatisierung zu parallelisieren – das nennt man Shifting left.

the modern lifecycle of software

Sobald die erste Anforderung definiert ist, durchlaufen wir unmittelbar die Phasen Planung, Implementierung, Test und Release für die Endnutzer, während andere Anforderungen parallel erstellt, geplant, implementiert, getestet und veröffentlicht werden. Wir möchten jede Phase für ein Feature so früh wie möglich beginnen. Anders gesagt: Agile und DevOps zielen darauf ab, möglichst viel Arbeit nach links zu verschieben.

Test-Driven Development (TDD)

Eine Möglichkeit für „Shifting left“ ist Test-Driven Development (TDD). Es wurde ursprünglich Anfang der 2000er Jahre „entdeckt“ und ist inzwischen ein fester Bestandteil des Werkzeugkastens guter Entwickler. Der größte Vorteil dieser Praxis besteht darin, dass ein Teil der Testarbeit – technische Unit-Tests – parallel zur Implementierung erfolgt. Das ist ideal, denn Code und die ihn überprüfenden Tests werden Hand in Hand fertiggestellt. Dadurch halten Entwickler höhere Qualitätsstandards ein.

implement and technical testing

Shifting left ermöglicht nicht nur die Parallelisierung von Arbeit, sondern schafft auch eine völlig neue Möglichkeit, Tests als Designwerkzeug für den implementierten Code zu nutzen. So entsteht von Beginn an besserer Code – zusätzlich dazu, dass Arbeit nach links verschoben wird.

Schauen wir uns anhand eines kleinen Python-Beispiels an, wie wir früher vor TDD gearbeitet haben.

Wir benötigen einen Thingamabob, der authentifizierte Netzwerkverbindungen entgegennimmt, damit wir damit etwas erledigen können. Auf Basis dieser einfachen Spezifikation könnten wir etwa Folgendes erstellen.

Und natürlich erstellen wir auch den dazugehörigen Unit-Test.

Prima, oder? Mit TDD können wir also sicherstellen, dass wir nie „vergessen“, auch den Testfall zu erstellen. Doch schauen wir uns an, was passiert, wenn wir zunächst nur den Testfall schreiben.

Ich brauche einen Thingamabob, um etwas zu erledigen.

Da ist er! Was kann ich nun implementieren, damit der Test erfolgreich ist ...

Offenbar muss ich meinen Code so strukturieren, dass die Verbindung im Hintergrund reibungslos hergestellt wird. Ich weiß: Dafür nutze ich die Context Manager von Python!

In diesem Beispiel haben wir eine deutlich bessere Schnittstelle für Thingamabob erstellt: Der Endnutzer – also der aufrufende Code – muss sich nicht um die Verwaltung der Verbindung kümmern. Die zweite Implementierung benötigt nicht nur weniger Codezeilen, sondern ist auch zukunftssicherer. Denn wenn sich die Verbindung auf irgendeine Weise ändert, bricht der Testfall nicht, da er lediglich prüfen soll, ob etwas erledigt wird. Das erste Beispiel wirkt vielleicht einfacher, ist es aber nicht. Der Testfall hat unsere Designentscheidungen zu besserem Code geführt.

Acceptance Test-Driven Development (ATDD)

TDD ist ein Prinzip, das die Implementierung von Code verbessert hat: Es verbindet nicht nur technische Tests mit der Implementierung und ermöglicht damit Parallelisierung, sondern hat auch eine völlig neue, unerwartete Arbeitsweise aufgezeigt.

Acceptance Testing ist unter vielen Namen bekannt, darunter User Acceptance Testing (UAT), End-to-End-Testing, Alpha-Testing und Beta-Testing. Neue Testautomatisierungstools ermöglichen es uns heute, diesen Testbereich zu automatisieren, der früher erst beginnen konnte, wenn die meisten oder sogar alle Implementierungsarbeiten abgeschlossen waren. Mit Open-Source-Tools wie Robot Framework oder Cucumber können wir die Interaktion der Endnutzer mit unserer Anwendung automatisieren, statt sie manuell durchzuführen.

Man könnte sich fragen, warum eine Praxis, die sich stark mit der Automatisierung manueller Tests beschäftigt, neben der vergleichsweise technischen Praxis von TDD vorgestellt wird. Ich versichere euch: Das liegt nicht nur daran, dass die Begriffe ähnlich klingen. ATDD ermöglicht uns ebenfalls, Arbeit nach links zu verschieben, die zuvor erst später stattgefunden hat.

Screen Shot 2019-01-30 at 15.31.46

Die Automatisierung dieser letzten Testphase nimmt Menschen manuelle Arbeit ab – eine der wichtigsten Säulen von DevOps. Wie bei TDD können wir noch weiter nach links verschieben, indem wir Acceptance Test-Driven Development (ATDD) einsetzen. Bei dieser Praxis beginnen wir viel früher als bisher mit dem Schreiben von Testfällen: bereits bei der Anforderungserhebung.

requirements and acceptance testing

Im Kern nutzt ATDD eine weitere bewährte Methode: User Stories. Damit definieren wir unsere Spezifikationen durch eine informelle Beschreibung in natürlicher Sprache aus der Perspektive unseres angenommenen Endnutzers.

The basic structure of user stories

Früher sah die Softwareentwicklung etwa so aus:

  1. Die Spezifikation einer Anforderung in einem Dokument festhalten

  2. Viel Zeit darauf verwenden, das Dokument zu verstehen, und nach zahlreichen Diskussionen die Implementierung auf Grundlage einer vagen Vorstellung davon planen, was gewünscht ist

  3. ...das Feature als Code implementieren...

  4. Noch mehr Zeit darauf verwenden herauszufinden, ob die Implementierung wie vorgesehen funktioniert und die ursprüngliche Anforderung erfüllt …

  5. (In der Regel) das Feature erneut und anders implementieren, da nun mehr Informationen vorliegen

  6. Neue Informationen kommen hinzu: Schritte 3–5 immer wieder wiederholen.

Ein Workflow für Acceptance Test-Driven Development (ATDD) sieht heute so aus:

  1. Die Spezifikation in einem einheitlichen Format als Testfälle formulieren, bis alle das Feature verstanden haben.

  2. Das Feature implementieren und dabei den Testfall automatisieren.

  3. Wenn neue Informationen auftauchen, die eine Änderung erforderlich machen, Schritt 1 wiederholen und fortfahren.

  4. Das Ergebnis durch Ausführen des Testfalls prüfen. Erledigt.

Beispiel mit Robot Framework

Wir profitieren nicht nur vom User-Story-Format, das uns hilft, das Problem besser zu verstehen. Wir richten die Diskussion über das Feature auch auf die Perspektive des Endnutzers aus. Das zwingt alle Beteiligten – Business, Design, Entwickler, Tester und Betrieb – dazu, das Gesamtbild zu betrachten und zu verstehen, warum sie die Arbeit überhaupt machen.

Sobald alle verstanden haben, worum es geht, wird der Testfall zu einem nachverfolgbaren Bestandteil jeder weiteren Phase des Lebenszyklus. Das bedeutet: Er wird zusammen mit dem Code im Versionskontrollsystem versioniert, dient als lebende Dokumentation der Business-Anforderung und kann jederzeit ausgeführt werden, um nachzuweisen, dass das Feature funktioniert.

TDD + ATDD

Ich habe gezeigt, wie technische Unit-Tests mit TDD Testfälle zu einem Werkzeug für das Code-Design machen. Ebenso ermöglicht ATDD nicht nur die Automatisierung der weitgehend manuellen Testphase, sondern rückt sie ins Zentrum der Anforderungsspezifikation.

Entwerft ihr mit TDD einfacheren Code? Fällt euch dank ATDD die Zusammenarbeit mit Business und Entwicklung leichter? Teilt uns eure Gedanken oder Vorschläge für künftige Themen, über die ich schreiben soll, auf unserer Kontaktseite mit.

Entdeckt das Schulungsangebot.

  • DevOps
  • CI/CD

Subscribe to our newsletter