PHP und UnitTests wie fange ich an?

Wer schon mal ein System gepatcht hat und dann die Seite nur noch 500 sagen gesehen hat, wünscht sich, der Fehler wäre vorher aufgefallen. Also müssen jetzt sofort UnitTests her. Aber wo anfangen? Und wie bekomme ich nur die Kopplungen zur DB, zum Solr oder sonstigen Komponenten weg?

OK, mal schön der Reihe nach:

Schritt 1: Grundstruktur

Wir führen hier zunächst eine Zwischenschicht ein, die für uns die Datenbankarbeit übernehmen wird.

Schritt 2: Datenbank mocken

Um unseren ersten Test durchführen zu können müssen wir jetzt die Datenbank simulieren. Die muss erst mal überhaupt nicht existieren, wir wollen einfach nur prüfen ob unsere zu testende Funktion auch die richtigen Operationen durchführt.

Ein wichtiger Teil der UnitTests sind sogenannte Mock-Objects. Damit erhalten wir die Kontrolle über Klassen, die von unserem Testsubjekt benötigt werden. Wir verwenden hier ganz allgemein PDO, aber das geht natürlich mit jeder anderen Klasse auch. Durch die beiden „false“ am Ende verhindern wir, dass der Original-Konstruktor von PDO aufgerufen wird. Damit benötigen wir keine real existierende DB für unseren Test mehr.

Irgendwie muss natürlich unsere zu testende Klasse die simulierte DB auch verwenden. Wer mit einem Framework arbeitet wird sich da leicht tun. Die DB ist irgendwo als Service definiert und wir automatisch „injected“. Es muss also lediglich dieser Service überschrieben werden. Wer global eine Datenbankverbindung hat und immer mit „global $db;“ arbeiten muss, kann das hier einfach genauso tun.
Der Rest muss die Datenbank in die Klasse reichen wie im Beispiel oben. Dazu sind dann vermutlich Anpassungen an der Klasse notwendig.

Schritt 3: Test durchführen

Der eigentliche Test passiert hier:

Hier sagen wir nun unserem Mock-Object was genau wir erwarten. Diese Erwartungen werden nach Testende von PHPUnit automatisch überprüft. Wir erwarten also folgendes: Die Funktion „query“ wird genau einmal aufgerufen „once()“ mit einem Parameter, der exakt unserem erwarteten SQL-Statement entspricht („equalTo()“).
Und schon haben wir unseren ersten Test ohne lästige DB erledigt.

Schritt 4: Weitere Möglichkeiten ausprobieren

Eine einfache Anwendung des Datenbank-Mocks haben wir jetzt gesehen, aber was haben wir denn da noch?

Andere Häufigkeiten

Zunächst kann natürlich eine anderen Häufigkeit erwartet werden. Es stehen zur Auswahl:

Ein Sonderfall ist

Damit können wir für verschiedene Aufrufe der selben Funktion unterschiedliche Erwartungen (zum Beispiel Parameter) definieren. Wichtig zu beachten ist, dass die Zählung der Aufrufe für die gesamte Klasse vorgenommen wird und nicht die einzelne Funktion.

Rückgabewerte

Natürlich erwarten unsere Testsubjekte auch Rückgaben von den DB-Funktionen. Auch hier bietet unser Mock die notwendigen Hilfsmittel.

Uns ist also erst mal egal wie oft fetch() aufgerufen wird und mit welchen Parametern das geschieht. Aber wir definieren einen Rückgabewert („returnValue“). Damit haben wir für unseren Test immer die gleichen Bedingungen und können überprüfen ob unser Testsubjekt auch immer das gleiche tut.

Andere Möglichkeiten sind:

returnValueMap() liefert von uns definierte Werte solange der Vorrat reicht. Für nachfolgende Aufrufe wird immer wieder der letzte Wert zurück gegeben.
returnCallback() übergibt an den Callback die Parameter exakt so wie sie das Testsubjekt an die eigentliche Funktion übergibt. Hier können wir also auch die Übergabeparameter noch einmal eingängiger testen als es mit ->with($this->equalTo()) möglich wäre. Des Weiteren kann die Rückgabe von den Parametern abhängig gemacht werden.

One thought on “PHP und UnitTests wie fange ich an?”

Kommentare sind geschlossen.