tl;dr - Zusammenfassung
Kontinuierliches Testen ist hilfreich in der testgetriebenen Entwicklung (TDD) für schnelles Feedback bei gleichzeitiger Beibehaltung des so genannten “Flows”. Drei unterschiedliche Beispiele zeigen wie kontinuierliches Testen den Kontextwechsel bei TDD minimieren kann.
Was ist TDD?
Testgetriebene Entwicklung (TDD) wird praktiziert um bei der Entwicklung kontinuierlich und in kleinen Schritten die Struktur des Codes zu verbessern, Regressionen zu verhindern und schnelles Feedback zu erhalten.
TDD unterscheidet drei Phasen. In der ersten Phase - “Red” - wird ein neuer Test geschrieben. Dieser Test beschreibt einen kleinen Teil der Fachlichkeit und er sollte bei der Ausführung erwartungsgemäß fehlschlagen. Jetzt folgt die zweite Phase - “ Green”. Hier wird nur soviel produktiver Code geschrieben bis die Tests wieder grün sind. Beim Refactoring, dem dritten Schritt, wird der Code und die Tests von Duplikationen befreit und strukturiert bis sie verständlicher wird. Beim Refactoring müssen die Tests _immer_ erfolgreich durchlaufen. Gerade in dieser Phase arbeitet man in kleinen Schritten und führt sehr häufig die Tests aus.
Und wo ist nun das Problem?
Bei allen drei Phasen müssen immer wieder die Tests ausgeführt werden. Praktisch bedeutet das jedesmal einen Kontextwechsel für den Entwickler. In diesem Wechsel werden typischerweise die folgenden Schritte ausgeführt:
- Der Code wird gespeichert
- Wechsel zum Test-Runner
- Die Tests werden gestartet
- Das Ergebnis wird abgewartet
- Wechsel zurück zum Editor
Dieser immer wiederkehrende Kontextwechsel beinhaltet viele kleine Schritte die per Tastatur oder Maus ausgeführt werden. Dabei ist man als Entwickler doch nur an dem schnellen Feedback interessiert und riskiert dafür den Verlust der Fokussierung.
Im schlimmsten Fall verliert man sogar den Flow - den Zustand der hoher Konzentration und absoluten Fokussierung. Sven Peters und Stefan Roock haben jeweils über Flow geschrieben.
Wie kann man das Problem lösen?
Alle fünf aufgezeigten Schritte haben keine eigenes und unabhängiges Ziel, sie werden für nur das Feedback gemacht. Die einzelnen Schritte sind alle nur Zwischenschritte zu der Antwort auf die Frage: “Laufen die Tests jetzt wie erwartet?”
Um eine Ergebnis zu erzielen, sollte auch maximal eine Aktion notwendig sein. Drei exemplarische Beispiele sollen das Prinzip verdeutlichen, wie mit nur einer Aktion alle aufgezählten Schritte erledigt werden.
Pragmatisch
Eine sehr einfache und pragmatische Lösung ist es diese Schritte per Makro in einen Befehl zu verpacken.
Ein Beispiel am Editor vim. Mit dem folgenden Befehl wird ein Makro für die Tastenkombination Strg-t aufgezeichnet:
:nnoremap <C-t> :w<cr>!nosetests<cr>
Anstatt einzeln zu speichern und den Test auszuführen, kann ich jetrzt Strg-T drücken. Es wird dann gespeichert und sofort meine Test gestartet
Manche Editoren oder IDEs lassen auch automatischen Builds zu. Ein Beispiel wie das noch mehr und schneller in den Editor integriert werden kann zeigt das Video von Gary Bernhardt in seiner beeindruckenden String Calculator Kata in Python
Wächter
Eine weitere Möglichkeit ist es unabhängig von dem Editor die Tests zu starten bzw. automatisch starten zu lassen. Wie soll das gehen? Um auf Änderungen im Dateisystem zu reagieren gibt es Werkzeuge wie Guard in Ruby oder watchdog in Python. Diese können nach einer Änderung eine Aktion ausführen.
Wie sieht das am Beispiel watchguard in der Praxis aus? Hier für habe ich ein Shell-Skript runtests.sh das zuerst die Tests startet und mir danach das Ergebnis per notify-send einblendet:
#!/bin/bash
nosetests
if [ $? -eq 0 ]
then
notify-send --icon=dialog-info --expire-time=100 "Tests erfolgreich";
else
notify-send --icon=dialog-warning --expire-time=250 "Tests kaputt";
fi
Das Skript wird in von watchguard bzw dem Befehl watchmedo gestartet wenn sich innerhalb des Projekts eine Datei verändert:
watchmedo shell-command -c runtests.sh -p "*.py" -R .
Der Fokus liegt auf dem Editor, das Terminal mit dem watchmedo bleibt im Hintergrund. Als Ergebnis nach einem Test sieht man dann eine kleine Benachrichtigung. Und nur bei unerwarteten Fehlermeldungen kann man schnell in die Konsole wechseln und nachforschen.
Das Beispiel benutzt für die Benachrichtigung notify-send unter Ubuntu, für Mac gibt es zBGrowl oder für Windows Notifu.
Integriert
Es gibt Erweiterungen für die Entwicklungsumgebungen die kontinuierliches Testen unterstützen. Für Eclipse gibt es JunitMax - von Kent Beck - oder Infinitest. Hier werden die Tests automatisch ausgeführt und fehlschlagende Tests als Fehler angezeigt - ohne das weitere Aktionen vom Entwickler notwendig wären. Carsten Mjartan beschreibt diese in seinem Blogeintrag Continuous Testing Tools (nicht nur) für Java – Infinitest vs. JUnitMax.
Besonders beeindruckt haben mich dioe Fähigkeiten von “Mighty Moose” für Visual Studio:
Fazit
Mit kontinuierlichem Testen kann ich bei TDD den Fokus von der Ausführung der Tests auf die Entwicklung zurückführen. Bei der Wahl wie ich meine Tests automatisiert starte gibt es eine große Auswahl an Möglichkeiten, selbst nur mit simplen Werkzeugen wie der Konsole und einfachem Editor kann man kontinuierlich testen und den Kontextwechsel minimieren.
Weiterführende Links:
- Kent Beck
TDD by Example
http://books.google.de/books/about/Test_Driven_Development.html?hl=de&id=gFgnde_vwMAC - Ben Rady,
Continuous Testing Explained:
http://blog.objectmentor.com/articles/2007/09/20/continuous-testing-explained - David Saff Michael und D. Ernst,
Reducing wasted development time via continuous testing:
http://www.cs.washington.edu/homes/mernst/pubs/wasted-time-issre2003.pdf - Carsten Mjartan,
Continuous Testing Tools (nicht nur) für Java – Infinitest vs. JUnitMax
http://blog.codecentric.de/2011/01/continuous-testing-tools-nicht-nur-fur-java-infinitest-vs-junitmax/ - Ben Rady and Rod Coffin,
Continuous Testing: with Ruby, Rails, and JavaScript:
http://pragprog.com/book/rcctr/continuous-testing - http://continuoustests.com/
- Ruby - Guard
https://github.com/guard/guard - Python - watchdog
http://pypi.python.org/pypi/watchdog










Wer würde nicht gern so schnell Neues lernen wie Neo im Film Matrix? Einfach ein paar Lernprogramme im Schnelldurchlauf „einspielen“ und schon ist man Kampfsportprofi, kann Hubschrauber fliegen und zig andere tolle Sachen…

