Zum Inhalt springen
L

Wikipedia · einfach zusammengefasst · Stand

Testgetriebene Entwicklung

Das Refactoring, also das Aufräumen im Code, führt zu weniger Fehlern; weil man dabei in kleinen Schritten vorgeht und stets entlang bestandener Tests …

Inhalt6 Abschnitte
  1. 1. Grundidee und Zweck
  2. 2. Unit-Tests und der TDD-Zyklus
  3. 3. System- und Akzeptanztests
  4. 4. Vorteile, Einsatz und Werkzeuge
  5. 5. Aufwand, Disziplin und Ausbildung
  6. 6. Grenzen und ergänzende Testarten

Grundidee und Zweck

Testgetriebene Entwicklung, auch testgesteuerte Programmierung oder englisch test first development beziehungsweise test-driven development (TDD), ist eine vor allem in der agilen Softwareentwicklung eingesetzte Methode. Dabei werden Softwaretests konsequent vor den Komponenten erstellt, die sie prüfen sollen. Die Tests beschreiben somit vorab das erwartete Verhalten und steuern die weitere Programmierung.

Bei klassischen Vorgehensweisen wie dem Wasserfall- oder V-Modell entstehen Tests parallel zum System, unabhängig davon oder erst danach. Dadurch kann schwer testbarer Code entstehen. Ursachen sind beispielsweise ein monolithischer Aufbau, Abhängigkeiten von Fremdkomponenten, Zeitdruck, mangelnde Disziplin oder die Konzentration von White-Box-Tests auf die innere Struktur des vorhandenen Codes. TDD soll solchen Problemen entgegenwirken und zugleich ein besser an die Aufgabe angepasstes, wartbares Softwaredesign fördern.

Laut Artikel können mit testgetriebener Entwicklung im Durchschnitt 45 Prozent aller Fehler erkannt oder vermieden werden. Beim alleinigen Einsatz von Unit-Tests sind es im Durchschnitt 30 Prozent.

Unit-Tests und der TDD-Zyklus

Beim Testen im Kleinen werden Unit-Tests verwendet. Eine Unit ist eine einzelne programmtechnische Einheit, etwa eine Klasse oder ein Modul. Bei der einfacheren Methode „tests first“ werden Unit-Tests vor dem Programmcode geschrieben. Mehrere Tests dürfen gleichzeitig fehlschlagen, und die Umsetzung des von einem Test geforderten Verhaltens kann verschoben werden. Diese Methode gilt als Vorstufe der eigentlichen testgetriebenen Entwicklung.

Bei TDD nach Kent Beck entstehen Tests und die getesteten Units dagegen parallel in kleinen Mikroiterationen von jeweils nur wenigen Minuten. Der Zyklus heißt Red-Green-Refactor:

• Red: Zuerst wird ein Test für ein neues Verhalten geschrieben, beginnend mit dem einfachsten Beispiel. Der Test kann auch einen bekannten Fehler oder eine neue Funktion betreffen. Da die Funktion noch fehlt, muss der Test zunächst fehlschlagen.

• Green: Der Programmcode wird mit möglichst geringem Aufwand so ergänzt oder verändert, dass anschließend alle Tests bestanden werden.

• Refactor: Danach wird der Code aufgeräumt. Wiederholungen werden entfernt, sinnvolle Abstraktionen eingeführt und Code-Konventionen eingehalten. Dabei darf kein neues, noch ungetestetes Verhalten hinzukommen. Nach jeder Änderung laufen die Tests erneut; schlägt einer fehl, darf die fehlerhafte Änderung nicht in den genutzten Code übernommen werden.

Dieser Zyklus wird wiederholt, bis bekannte Fehler behoben sind, die gewünschte Funktionalität vorhanden ist und keine weiteren sinnvollen, möglicherweise scheiternden Tests mehr gefunden werden. Die Tests bleiben anschließend erhalten und prüfen bei späteren Änderungen, ob das bereits erreichte Verhalten weiterhin funktioniert.

Jede Änderung in der Green-Phase, auch Transformation genannt, muss zu einer allgemeineren Lösung führen und darf nicht nur den aktuellen Testfall auf Kosten anderer Fälle behandeln. Immer genauere Tests treiben den Code dadurch zu allgemeineren Lösungen. Die Transformationsprioritäten können außerdem zu effizienteren Algorithmen führen. Insgesamt wirkt die konsequente Methode als evolutionärer Entwurf: Jede kleine Änderung entwickelt das System weiter.

System- und Akzeptanztests

Beim Testen im Großen werden Integrations-, System- oder Akzeptanztests eingesetzt. Beim sogenannten outside-in TDD werden Systemtests vor dem System entwickelt oder zumindest spezifiziert. Die Aufgabe der Entwicklung besteht dann nicht nur darin, schriftliche Anforderungen umzusetzen, sondern die festgelegten Systemtests zu bestehen.

Die akzeptanztestgetriebene Entwicklung (ATDD) ist mit TDD verwandt, hat aber eine andere Funktion und Vorgehensweise. Sie dient als Kommunikationswerkzeug zwischen Kunden beziehungsweise Anwendern, Entwicklern und Testern und soll sicherstellen, dass Anforderungen gut beschrieben sind. Ihre Tests müssen deshalb auch für Nicht-Entwickler lesbar sein. Eine Automatisierung ist bei ATDD nicht vorgeschrieben, wäre aber für Regressionstests hilfreich. Regressionstests prüfen, ob bereits funktionierende Eigenschaften nach Änderungen weiterhin funktionieren. Tests für TDD lassen sich in vielen Fällen aus ATDD-Tests ableiten.

Alle TDD-Arten streben eine möglichst vollständige Testautomatisierung an. Die Tests sollen einfach, möglichst „per Knopfdruck“, und schnell ausführbar sein. Unit-Tests sollen nur wenige Sekunden dauern, Akzeptanz- oder Systemtests höchstens einige Minuten und nur ausnahmsweise länger.

Vorteile, Einsatz und Werkzeuge

Die Tests liefern eine boolesche, also aus zwei möglichen Zuständen bestehende Metrik für die Erfüllung der Anforderungen: Sie werden entweder bestanden oder nicht. Beim Refactoring entstehen durch kleine, ständig geprüfte Schritte weniger neue Fehler; auftretende Fehler lassen sich leichter eingrenzen. Weil Tests schnell verfügbar sind, arbeiten Entwickler meist an einem korrekten System und können sich auf die aktuelle Teilaufgabe konzentrieren.

Der Bestand automatisierter Tests dokumentiert das System als „ausführbare Spezifikation“: Das geforderte Verhalten liegt in lesbaren und unmittelbar ausführbaren Tests vor. Bei akzeptanztestgetriebener Entwicklung kann diese Dokumentation auch für Nicht-Entwickler verständlich sein. TDD begünstigt außerdem kleinere und spezifischere Klassen oder Module, lockerere Kopplungen sowie einfachere Schnittstellen. Dadurch kann der Code leichter geändert und erweitert werden.

Empirische Studien ergeben allerdings kein einheitliches Bild. Bei unerfahrenen Entwicklern wurde teilweise eine geringere Defektrate, aber zugleich ein höherer Zeitaufwand nachgewiesen. Andere Studien fanden keinen Qualitätsgewinn.

TDD ist ein wesentlicher Bestandteil von Extreme Programming (XP) und anderen agilen Methoden. Sie wird auch außerhalb davon genutzt, häufig zusammen mit Paarprogrammierung. Zum Üben dienen oft Katas.

Benötigt werden vor allem Build-Automatisierung, beispielsweise mit CruiseControl oder Jenkins, und eine integrierte Entwicklungsumgebung für schnelle Testzyklen. In Java werden häufig Ant, Maven oder Gradle sowie JUnit verwendet; Beispiele für andere Sprachen sind PHPUnit für PHP und Ceedling, Unity und CMock für C. Mock-Objekte sind programmierte Stellvertreter, die abhängige Komponenten simulieren. Sie ermöglichen es, Einzelkomponenten unabhängig zu testen, und fördern einfache Abhängigkeiten. Für Akzeptanz- und Systemtests werden etwa Framework for Integrated Test oder Cucumber verwendet. Fitnesse ist eine verbreitete FIT-Variante und verbindet einen Wiki-Server mit einer Umgebung zur Erstellung und Ausführung von Tests.

Aufwand, Disziplin und Ausbildung

Der wichtigste Einwand gegen TDD ist der vermeintlich hohe Aufwand. Ein großer Teil der Programmierarbeit besteht jedoch ohnehin darin, gedanklich die zu erfüllenden Fälle zu bestimmen. Diese Fälle unmittelbar vorher durch wenige Testzeilen festzuhalten, verursacht daher nur begrenzten Zusatzaufwand und kann die Gedanken strukturieren sowie die Codequalität verbessern. Die Notwendigkeit, zuerst einen Testfall festzulegen, beeinflusst außerdem die Reihenfolge der implementierten Funktionen und kann den Kundennutzen stärker berücksichtigen.

Automatisierte Tests gelten als Sicherheitsnetz für spätere Änderungen. Ohne hohe Testabdeckung ist ein System anfälliger für Fehler bei Weiterentwicklung und Wartung. Mit Übung kann TDD bereits bei der ersten Implementierung weniger Aufwand verursachen als eine schnelle Lösung ohne automatisierte Tests. Dieser Vorteil wird nach übereinstimmender Ansicht umso größer, je langlebiger und häufiger verändert ein System ist. Nachträgliche Tests sind wesentlich aufwendiger, weil Anforderungen und Programmzeilen erneut analysiert werden müssen; eine vergleichbare Testabdeckung ist dann aus Kosten- und Aufwandsgründen kaum realistisch.

TDD kann dennoch falsch angewendet werden. Unerfahrene Programmierer empfinden es mitunter als schwierig, etwas noch nicht Vorhandenes zu testen, und vernachlässigen deshalb die Regeln. Besonders bei agilen Methoden wie XP kann dies den Entwicklungsprozess schwer beeinträchtigen. Zu wenige Unit-Tests bieten keine ausreichende Absicherung für Refactoring und Qualität. Paarprogrammierung und Schulungen können helfen.

Wenn Änderungen am Produktionscode unverhältnismäßig viele Unit-Tests scheitern lassen, liegt dies in der Regel daran, dass die getestete Unit nicht ausreichend getrennt wurde und die Tests nicht atomar sind. Atomare Tests prüfen jeweils eine klar abgegrenzte Funktionseinheit. Entwickler müssen deshalb lernen und üben, Anforderungen in solche Einheiten zu zerlegen.

Grenzen und ergänzende Testarten

Auch eine stark testorientierte Entwicklung kann nicht jeden Fehler finden. TDD ersetzt deshalb andere Testarten nicht:

• Fehler im Zusammenspiel mehrerer Programme oder Programmteile lassen sich eher durch Integrationstests entdecken.

• Ob eine Software gebrauchstauglich ist, kann TDD nicht feststellen; dafür eignen sich Usability-Tests.

• Ob funktionale und nicht-funktionale Anforderungen erfüllt sind, lässt sich mit Unit-Test-TDD häufig nicht ausreichend prüfen. Hierfür werden akzeptanztestgetriebene Verfahren wie Behavior Driven Development oder Systemtests empfohlen.

Da keine einzelne Testart und keine Vorgehensweise alle Fehler aufdecken kann, sollten in den meisten Fällen mehrere Testarten und fehlervermeidende Methoden miteinander kombiniert werden.

Lernvideos zu Testgetriebene Entwicklung

Weiterlesen

Softwaretest Ein Softwaretest prüft und bewertet Software auf Erfüllung der für ihren Einsatz definierten Anforderungen und misst ihre Qualität. Wasserfallmodell Ein Wasserfallmodell ist ein lineares (nicht iteratives) Vorgehensmodell, das insbesondere für die Softwareentwicklung verwendet wird und das in … V-Modell Ähnlich dem Wasserfallmodell organisiert es den Softwareentwicklungsprozess in Phasen. Zusätzlich zu diesen Entwicklungsphasen definiert das V-Modell auch … Softwaredesign Softwaredesign (auch Softwarekonstruktion) ist der Konstruktionsprozess zur Implementierung einer Software-Lösung. Üblicherweise vollzieht sich die … Modultest Ein Modultest (auch von englisch unit test als Unittest oder als Komponententest bezeichnet) ist ein Softwaretest, mit dem einzelne, abgrenzbare Teile von … Refactoring Refactoring ist ein zentraler Bestandteil der Agilen Softwareentwicklung. Dort wird meist von „kontinuierlichem“ Refactoring oder „kompromisslosem“ Refactoring … Programmierstil Er gilt als Teilaspekt von Softwarequalität, der insbesondere die Verständlichkeit und Wartbarkeit von Software, dies sind Kriterien für Softwarequalität gem. Integrierte Entwicklungsumgebung Eine integrierte Entwicklungsumgebung (IDE, von englisch integrated development environment) ist eine Sammlung von Computerprogrammen, mit denen die … Java (Programmiersprache) Java ist eine objektorientierte Programmiersprache und eine eingetragene Marke des Unternehmens Sun Microsystems, welches 2010 von Oracle übernommen wurde. C (Programmiersprache) C ist eine imperative und prozedurale Programmiersprache, die der Informatiker Dennis Ritchie in den frühen 1970er Jahren an den Bell Laboratories entwickelte.