Test Driven Development ist die Technik des 21.Jahrhunderts, die meine Art Software zu entwickeln mindestens so nachhaltig geprägt hat wie die objektorientierte Programmierung (OOP) oder das Buildframework Maven.
Was bedeutet testgetriebenes Entwickeln?
Ich will hier natürlich nicht die xte Erläuterung liefern, was TDD bedeutet und wie es läuft. Andererseits kann ich nicht über die Technik des tesgetriebenen Entwickelns sprechen, ohne den Kern dieser Technik dargestellt zu haben.
Beim testgetriebenen Entwickeln geht es nicht um das Design oder den Entwurf der Anwendung, der Komponenten. Dieser muss vorher passieren. Ich komme also auch mit TDD nicht umhin, ein paar UML-Skizzen zu zeichnen, die mir vorgeben, was die Aufgabe der jeweiligen Komponenten (Klassen/Methoden) ist.
Dies soll an einem kleinen Beispiel Schritt für Schritt erläutert werden.
Aber vorneweg der Hinweis auf die 8 Gründe für TDD, für alle die, die Argumente für TDD brauchen.
Die Aufgabe sei, eine Klasse zu schreiben, die arabischen Zahlen (1,2,3,…) in römische Zeichen umwandelt, so wie hier beschrieben.
Der Entwurf ist hier denkbar einfach. Ich benötige eine Klasse Arabic2RomanConverter, mit einer public Methode String convert(int arabicNumber) throws IllegalArgumentException.
Die Methode soll für 0 bis 3000 die römischen Zeichen liefern und in allen anderen Fällen eine IllegalArgumentException werfen.
Nun kann ich mit dem Test-First Ansatz starten
package de.mike.examples;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import org.junit.Test
public class Arabic2RomanConverterTest {
@Test
public void test1000() {
Arabic2RomanConverter converter = new Arabic2RomanConverter();
assertEquals("M", converter.convert(1000));
}
}
Jeder Test gliedert sich in maximal 4 Vorgänge:
- Test preparation
- Test execution
- Test assertion/verification
- Test clean up
In meinem einfachen Fall findet die Testvorbereitung in Zeile 12 statt. Die Ausführung und Überprüfung in Zeile 13. Das Aufräumen übernimmt der Garbage Collector von Java für mich.
Da die Klasse Arabic2RomanConverter noch nicht existiert, ist der Test rot (und zwar im besten Sinne des TDD).
Rote Tests sollten so schnell wie möglich grün gemacht werden.
Der einfachste Fall, dies hier zu tun, ist die folgende Klasse:
package de.mike.examples;
public class Arabic2RomanConverter {
public String convert(int arabicNumber) {
return "M"
}
}
Warum soll der rote Test so schnell wie möglich grün werden?
Nun dafür gibt es vielerlei Gründe. Allen voran läuft etwas nicht, was laufen sollte, und das widerstebt einem guten Software Entwickler stets.
Des Weiteren verfolge ich als Clean Code Developer immer auch das YAGNI (You ain’t gonna need it) Prinzip. Dies lehrt mich, dass die Rückgabe des konstanten Werts „M“ an dieser Stelle ausreicht, weil es noch keine weiteren Vorgaben durch Tests, und nur davon lasse ich mich treiben, gibt.
Dieses sich von den Tests treiben zu lassen, hat den Vorteil, dass ich mir bei der Implementierung NICHT mehr den Gedanken machen muss, was mein Programm zu leisten hat, sondern mich darauf konzentrieren kann, wie ich es implementiere.
Warum Generationen von Entwicklern nicht versucht haben, dies früher zu trennen, sondern immer noch mit dem Debugger im Gepäck alle Probleme auf einmal lösen wollten, ist mir, seit ich testgetrieben entwickeln kann und darf, schleierhaft.
Aber vorher kümmere ich mich um die wichtigste haltlose Bemerkung der Software Entwickler. Immer wieder höre ich in meinen Schulungen den Satz:
Das ist natürlich Quatsch.
ALLE testen. Die Frage ist nur wie?!
Debugging ist White-Box-Testing.
Sehr zeitaufwändig, oftmals technisch nicht so ohne Weiteres realisierbar – denken wir nur mal ans Remote Debugging einer Serveranwendung. Und vor allem ist es nicht konsistent.
Ich habe noch niemanden gesehen, der sich in einer Excel-Tabelle erwartete Werte von Variablen zwischengespeichert hat, um zu sehen, ob dies in einem nachfolgenden Debugging Durchlauf immer noch so ist.
Ausgaben erstellen ist eine Krankheit.
Entwickler, die mit System.out.println (Java) oder var_dump (PHP) oder echo, Werte ausgeben lassen, um zu prüfen, ob sich das Programm richtig verhält, doktorn einfach nur an ihrem Programm rum.
Sie wollen nicht wirklich eine lauffähige Anwendung, sondern haben nur das Bedürfnis, ein korrektes Ergebnis zu sehen. Wie dieses zustande kam, ob alle weiteren Bedingungen erfüllt sind, spielt nach der visuellen Kontrolle der Ausgabe keine Rolle mehr.
Das ist vom Verhalten ein bisschen so, wie früher beim Abschreiben in den Matheklausuren.
Man versucht einen Rechenweg, schreibt zunehmend undeutlicher und kopiert am Ende das Ergebnis des kompetenteren Nachbarn. Fertig.
Im Folgenden kommen noch weitere Beiträge rund ums Thema TDD: