• Unit-Testing – ein essentieller Teil der Softwareentwicklung

    Es gilt auch für kleine Tools, die auf Grund der Größe noch überschaubar sind, dass Testing im Späteren, Arbeit erspart. Vorallem wenn die Code Basis für das Tool sehr klein ist, ist es leicht eine hohe Test-Coverage zu erreichen.

    Die Erkenntnis das 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 uraltem 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 (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 auf Grund 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 implemetiert, 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.

    phpunit1

     

     

     

     

    Zum Testen hab ich einen Code direkt von der Seite von phpunit.de in eine Datei SimpleTest.php kopiert

    
    <?php class StackTest extends PHPUnit_Framework_TestCase { public function testEmpty() { $stack = array(); $this->assertEmpty($stack);
    
            return $stack;
        }
    
        /**
         * @depends testEmpty
         */
        public function testPush(array $stack)
        {
            array_push($stack, 'foo');
            $this->assertEquals('foo', $stack[count($stack)-1]);
            $this->assertNotEmpty($stack);
    
            return $stack;
        }
    
        /**
         * @depends testPush
         */
        public function testPop(array $stack)
        {
            $this->assertEquals('foo', array_pop($stack));
            $this->assertEmpty($stack);
        }
    }
    ?>
    
    

    Der Test kann über die Commandline mit „phpunit SimpleTest.php“ ausgeführt werden.

    phpunit2

     

     

     

     

     

     

     

    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.

    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <phpunit>
        <testsuites>
            <testsuite name="SimpleTests">
                <file>SimpleTest.php</file>
            </testsuite>
        </testsuites>
    </phpunit>
    
    

    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.

    phpunit3

     

     

     

     

     

     

     

     

     

     

     

    Fazit

    Vorallem 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.