Eine Einführung in Unit-Testing für Extensions: Grünes Gefühl mit TYPO3
Irgendwann gelangt jeder Entwickler an den Punkt, an dem er überlegt,
ob es sich eher lohnt, den angestaubten Code zu überarbeiten
oder noch einmal frisch von vorne zu beginnen. Vor allem bei der
Übernahme eines fremden Projekts überwiegt oft der Drang
nach einem Neuanfang. Es würde meist viel zu lange dauern, den Code
aufzuräumen und bei jeder kleinen Änderung könnten
sich Fehler einschleichen, die später aufwändig nachvollzogen und bereinigt werden
müssten.
Die
Arbeit an einer API (Application Programming Interface) ist besonders heikel, denn dort stellt sich die
Frage nach einem Neuanfang erst gar nicht: Es gilt, möglichst
abwärtskompatibel zu bleiben, denn viele andere Anwendungen sind
von der Schnittstelle abhängig. Die Aufräumarbeiten in
solchen Programmteilen gleichen daher oft dem Spaziergang auf einem
Minenfeld.
Programmieren mit Netz
Die Lösung für diese
Probleme heißen „Refactoring“ und „Unit Testing“. Bei „Refactoring“ handelt
es sich um die Veränderung der inneren Struktur eines
Programms, bei dem sich das äußere Verhalten nicht
verändert. „Unit Tests“ dienen dabei als Sicherheitsnetz und geben
dem Entwickler eine Rückmeldung darüber, ob einzelne Teile
seines Programms noch die gewünschten Resultate liefern.
Unit Tests überprüfen
jeweils einen ganz bestimmten Teil einer Software, typischerweise das
Ergebnis einer oder mehrerer Methoden. Funktionale Tests, die hier
nicht behandelt werden, überprüfen hingegen die Funktionen
einer Software als Gesamtheit aus Sicht eines Anwenders.
Unit Testing für TYPO3
PHPUnit [1] von Sebastian Bergmann ist ein Unit
Testing Framework das es ermöglicht, eine große Reihe von
Tests zusammenzufassen und nacheinander ablaufen zu lassen.
T3Unit ist eine Erweiterung für TYPO3, die
auf PHPUnit2 aufbaut und um ein Interface sowie einige Funktionen
erweitert ist, die speziell für TYPO3 notwendig sind. Die Extension
basiert auf PHP5 und wurde für das Refactoring des Extension
Repositories entwickelt. Sie wird auf der TYCON3 im September
vorgestellt und veröffentlicht.
Ein Hello-You-Beispiel
Am besten verwendet man Unit-Tests bereits bei der Entwicklung von neuem Code und nicht erst beim Refactoring.
Angenommen es soll eine Funktion geschrieben werden, die einen
Namen als Parameter akzeptiert und als Resultat „hello $name“
liefert. Bevor man diese Funktion programmiert, würde man einen Test schreiben, der die spätere Methode überprüft:
public function test_helloYou() { $exampleObj = new tx_example; $result = $exampleObj->helloYou ('robert'); self::assertEquals ($result, 'Hello robert', 'The result of helloYou() was not as expected!'); }
Listing 1
In Zeile 2 wird eine Instanz der Klasse erzeugt, die getestet werden soll, um danach die zu testende Methode aufzurufen und das
Resultat zu speichern. Schließlich wird eine PHPUnit-Funktion
aufgerufen, die das gelieferte Ergebnis mit dem Soll-Ergebnis
vergleicht – wenn dieses vom erwarteten Wert abweicht wird eine
Fehlermeldung ausgegeben.
Beim Ausführen dieses Tests wird der PHP-Interpreter
mit einem „Fatal Error“ darauf aufmerksam machen, dass die Klasse
„tx_example“ gar nicht existiert. Diese muss zunächst angelegt werden:
class tx_example { public function helloYou ($name) { } }
Listing 2
Nach erneutem Aufrufen des Unit-Tests wird folgende
(erwartete) Fehlermeldung ausgegeben:
Der Unit-Test ist nicht erfüllt, da die Methode „helloYou“ kein Ergebnis zurück liefert, der Unit-Test jedoch eines erwartet.
Im letzten Schritt sorgen wir nun dafür, dass der Test sein
erwartetes Ergebnis erhält:
class tx_example { public function helloYou ($name) { return 'Hello '.$name; } }
Listing 3
Die TYPO3-Extension „T3Unit“ belohnt erfolgreiche Testverläufe mit einem grünen Fortschrittbalken
im Backend:
Test
Driven Development
Das Besondere an diesem Vorgehen ist, dass ein Test
geschrieben wird, bevor die zu testende Funktion überhaupt existiert. Man konzentriert sich von Anfang an auf das gewünschte
Ergebnis und sorgt so dafür, dass dieses auch geliefert
wird.
Während der weiteren Arbeit sammeln sich so eine ganze Reihe von
Tests an, die immer wieder ausgeführt werden. Auf diese Art und Weise
kann sichergestellt werden, dass alle wichtigen Funktionen auch nach
größeren Änderungen im Quellcode korrekt ablaufen.
Die Methode des „Test Driven Development“ [2] ist ein Baustein des Extreme Programming
(XP) [3], das eine bessere Produktivität und Erfolg von
Softwareprojekten zum Ziel hat.
Fazit
Unit
Testing ist weit mehr als ein gut gemeinter Trend. Viele Aufgaben, wie die
Umstrukturierung existierenden Codes, sind ohne solide Tests
zeitaufwändig und schwer kontrollierbar. Auch wenn es auf den ersten
Blick nicht so aussieht wird die zusätzliche Arbeit für die
Programmierung eines Tests schnell mit einem großen Zeitgewinn durch
den Wegfall langer „Debug-Sessions“ belohnt.
Ein weiterer Faktor, der nicht zu unterschätzen ist, scheint
psychologischer Natur zu sein: Unit Tests geben dem Entwickler eine gewisse
Sicherheit und Souveränität. Wer eine Zeit lang mit Tests gearbeitet
hat, wird das gute Gefühl beim Erscheinen des grünen Balkens nicht
vermissen wollen. Hektische „Debug-Sessions“ vor dem Launch einer Website sollten somit der Vergangenheit angehören.