Unit-Testing – ein essenzieller Teil der Softwareentwicklung
Es gilt auch für kleine Tools, die aufgrund der Größe noch überschaubar sind, dass Testing im Späteren, Arbeit erspart. Vor allem wenn die Code-Basis für das Tool sehr klein ist, ist es leicht eine hohe Test-Coverage zu erreichen.
Die Erkenntnis, dass Unit-Testing die Software-Qualität erhöht und Refactoring vereinfach, kann in vielen Büchern in Blogposts gelesen werden.
Wenn man allerdings selbst nicht die Qual gehabt hat an einem Stück Legacy-Code aus dem Mittelalter zu arbeiten, dann sind das bloß Informationen von anderen Personen.
Hier gilt das Sprichwort „Lernen durch Schmerzen“.
Die Geschichte vom Legacy-Code
Vor Kurzem wollte ein Kunde eine kleine Änderung in einem uralten Projekt durchführen. Den Code hab ich vor gefühlt 100 Jahren geschrieben in PHP, ja in PHP.
Als Klassiker, weil „man“ es ja damals nicht besser wusste, gibt nur es eine Datei, welche die Hauptlogik beinhaltet.
Kurze Fakten (und ja ich fühle gerade noch immer die Schmerzen, während ich diesen Post schreibe)
- 1 Klasse (immerhin eine Klasse)
- 40 Methoden
- 934 Lines of Code
- 91 Zeilen Comments (ein Großteil davon sind auskommentiere Code-Zeilen)
Die ewige Leier testbarer Code, Struktur, readable Code, bla bla bla möchte ich euch hier ersparen. Dafür gibt es genügend Bücher wie z.b. „Clean Code“ und „The Clean Coder“ von Robert C. Martin, die auf jeder Liste eines Softwareentwicklers stehen sollten.
Es sollte aufgrund der Fakten recht klar sein, dass dieses Stück Software (falls man es so nennen darf) ein Untier der Finsternis ist und 8 Jahre später davon kein Stück Erinnerung mehr übergeblieben ist, was zum Geier ich mir dabei gedacht habe.
Refactoring des ganzen Codes für zwei kleine Änderungen? Kurz gesagt ich hab mich dafür entschieden die Methoden, die von den Änderungen betroffen sind, neu zu schreiben.
Für diesen Vorgang wären Unit-Tests auch ganz nett, damit der derzeitige Outcome der Methode nach dem refactoring noch immer gleich ist wie davor.
So wie in den meisten Sprachen gibt es auch in PHP ein Testing-Framework. „PHPUnit“ (Danke Sebastian Bergmann, Author von PHPUnit)
PHPUnit in Action
Für alle, die sich von der Geschichte angesprochen fühlen (ich hoffe, es ist niemand) gibt es hier eine kleine Zusammenfassung, wie mit PHPUnit gearbeitet, Tests implementiert, Test-Suites definiert und ausgeführt werden können.
Um es sich das Leben zu erleichtern, sollte man eine IDE verwenden. In meinem Fall ist das IntelliJ Ultimate. Für die reine PHP-Entwickler-Welt gibt es auch Webstorm welche auf IntelliJ basiert.
Falls jemand eine IDE verwendet und unbedingt alles in Notepad schreiben will, ich führe die Tests auch über die Commandline aus
PHPUnit kann über PEAR oder phar installiert werden oder einfach über Github herunterladen und dann in den OS-Pfad eintragen. PHPUnit
Ist das erledigt, dann in der Commandline „phpunit –version“ eintippen.
Zum Testen hab ich einen Code direkt von der Seite von phpunit.de in eine Datei SimpleTest.php kopiert.
Der Test kann über die Commandline mit „phpunit SimpleTest.php“ ausgeführt werden.
Test-Suites
In der oben genannten Variante kann immer nur ein Test auf einmal ausgeführt werden. Umso umfangreicher das Projekt wird, desto mehr Tests kommen zusammen.
Damit diese hintereinander ausgeführt werden können gibt es Test-Suites welche über ein XML-Datei gesteuert werden.
Die XML-Datei wird per convention phpunit.xml benannt.
Jetzt muss in diesem Ordner nur mehr der Befehl „phpunit“ in der commandline eingegeben werden. PHPUnit liest von selbst die XML-Configuration-Datei ein und führt die angegebenen Tests aus.
Fazit
Vor allem wenn man Legacy-Code ändern muss und keine Tests vorhanden sind, ist es sehr empfehlenswert Tests nachzuschreiben.
Den gesamten Umbau des alten Tools wollte ich hier nicht niederschreiben, da es für mich selbst schon schmerzvoll genug war den Code zu lesen.
Einer der wichtigsten Punkte von Testing: Alle geänderten Code-Teile wurden mit Tests versehen. Dadurch ist ein Vertrauen in die Funktionalität entstanden, sodass der Code ohne weitere manuelle Test am Live-System deployed wurde.
Es soll das Ziel sein, die geschriebene Software jederzeit in einem Stand zu halten, der zu jedem Zeitpunkt ausgeliefert werden kann. Das kann nur mit guter Test-Coverage eingehalten werden.