Unit Testing in Laravel 5.5 – Unit Tests mit PHPUnit

Unit Testing in Laravel 5.5 – Unit Tests mit PHPUnit

Unit Testing ist wichtig und das scheint Dir schon bewusst zu sein, da Du es bis zu diesem Artikel geschafft hast. Die Gründe Unit Tests in Softwareprojekte zu integrieren wurden schon oft erläutert und sind Dir vormutlich auch bereits bekannt. In diesem Artikel werde ich Dir zeigen, wie Du Unit Tests mit dem PHP Test-Framework PHPUnit 6.4 in dem PHP Framwork Laravel 5.5 integrierst. Du wirst in Deinem Laravel Projekt über Artsian Unit Tests anlegen und diese mit Test-Logik befüllen. Danach zeige ich Dir noch, wie Du automatisch ansehliche Code Coverage Reports für Dein Laravel Projekt generieren kannst, und dass alles mit Hilfe von PHPUnit. So hast Du immer die Testabdeckung Deines PHP Codes im Auge. Zum Schluss ergänze ich noch einige Fehler, die auftreten können, wo deren Ursprung oft nicht leicht zu ermitteln ist.

Einführung in das Unit Testing in Laravel

Laravel liefert von Haus aus Unit Testing und Integrationstest (Feature Tests) Methoden aus. Das starke PHP Test Framework PHPUnit ist fest in Laravel integriert und wird in der aktuellen Laravel Version 5.5 mit der Version 6.4 ausgeliefert. PHPUnit 6.4 unterstützt PHP 7.0 und PHP 7.1.
PHPUnit wird über den PHP Paketmanager Composer ausgeliefert und liegt nach dem „install“ Befehl im Verzeichnis „vendor/bin/“ (phpunit.php).
Ebenfalls mit an Board ist eine von Laravel bereitgestellte PHPUnit Konfigurationsdatei „phpunit.xml“. Diese liegt im Basisverzeichnis Deines Projektes. Über die „phpunit.xml“ kannst Du „environment“ Variablen überschreiben, „Testsuites“ für unterschiedliche Test-Kategorien anlegen und vieles mehr. Hier wirst Du später auch den automatischen PHP Code Coverage Report konfigurieren.
Laravel stellt in der „phpunit.xml“ Konfiguration bereits Test-Suites für Unit Tests und Integrationstests (Feature Tests) bereit. In Deinem Laravel-Projekt findest Du im Verzeichnis „tests“ bereits die beiden Test-Suite Verzeichnisse „Unit“ und „Feature“ in denen Du später die jeweiligen Tests hinterlegen kannst.
Im „tests“ Verzeichnis sind neben den Test-Suites auch die zwei Klassen „TestCase.php“ und „CreatesApplication.php“ hinterlegt. Diese „booten“ für Dich während der Tests die Laravel-Anwendung. Näheres dazu aber in den folgenden Abschnitten.

Laravel Testumgebung

Wenn Du Deine Tests mit PHPUnit ausführst, läuft die Laravel-Anwendung durch die überschreibenden Environment Variablen der „phpunit.xml“ im „Test-Modus“. Innerhalb dieses „Test-Modus“ ändert Laravel automatisch den Cache Treiber in den Modus „array“. Der Treiber dient zur Cache und Session-Verwaltung. Den Treiber kannst Du auch selber anpassen. Du findest ihn im Verzeichnis „config“ unter dem Name „cache.php“. Der „array“ Modus sorgt dafür, dass der Cache und die Sessions nicht persistent gespeichert werden (d.h. in der Datenbank oder im Dateisystem).
Du kannst die Konfiguration nach Deinen Wünschen anpassen und um weitere Einstellungen erweitern. Wichtig ist nur, dass Du nach vorgenommenen Änderungen den Laravel Konfig-Cache leerst. Dies kannst Du mit Artisan über den Befehl „config:clear“ tun:

Einen Unit Test in Laravel anlegen und Tests ausführen

Wie bei fast allem hilft Dir auch hier das Laravel Tool Artisan aus. Du kannst den „make“ Befehl mit dem Parameter „test“ ausführen und einen Namen für den Test angeben. Wie das in der Konsole aussieht siehst Du anhand des folgendne Beispiels:

Über den Zusatz „–unit“ wird ein Unit Test angelegt, lässt man ihn weg erhält man einen Integrationstest / Feature Test. Der Test wurde im jeweiligen Ordner angelegt. In diesem Beispiel wurde der Test im Unit Test Ordner abgelegt.
Wenn Du den Test öffnest kannst Du mit Hilfe aller PHPUnit Funktionen Unit Tests erstellen um Deine Code Units zu testen. Hier siehst Du noch mal den angelegten Unit Test:

Solltest Du Deine eigene „setUp“ Funktion zum vorbereiten Deiner Tests erstellen, dann musst Du daran denken, die Funktion „parent:setUp“ mit aufzurufen, damit die Tests funktionieren.
Um nun Deinen frisch angelegten Unit Tests auszuführen, musst Du PHPUnit ausführen. Dazu gibt es mehrere Wege. Im Falle, dass Du PHPUnit nicht installiert hast, kannst Du die von Laravel mitgelieferte PHPUnit Datei „vendor/bin/phpunit.php“ über den folgenden Befehl in Deinem Laravel-Projektverzeichnis nutzen:

Die zweite Möglichkeit ist, dass Du Dir PHPUnit in der benötigten Version 6.4.3 installierst und PHPUnit dann einfach über den folgenden Befehl in Deinem Laravel-Projektverzeichnis ausführst:

Danach solltest Du ein ähnliches Ergebnis wie folgendes erhalten:

Komplettes Beispiel für Unit Tests in Laravel

Um das Ganze für Dich noch ein Stück greifbarer zu gestalten, werde ich Dir anhand von „Produkten“ zeigen, wie Du Deine Unit Tests aufbauen kannst. Du wirst in diesem Abschnitt ein Produkt Model und eine zugehörige Migration anlegen und einen passenden Controller dafür genierieren. Im Controller wirst Du passente CRUD (Create, Read, Update, Delete) Operationen, sowie die „Kaufen“ Funktion integrieren, die die Anzahl des gekauften Produktes reduziert.
Diese Funktionen wirst Du im Anschluss mit Unit Tests testen. Du wirst außerdem die „phpunit.xml“ um Environment Konfigurationen erweitern, damit nicht die „produktive“ Datenbank, sondern eine einfache SQLite Datenbank zum Testen verwendet wird. Wichtig ist, dass Du Dir SQLite3 und die PHP Extension zu SQLite3 installierst, sollte das nooch nicht der Fall sein. Unter Linux kannst Du dies mit den folgenden drei Befehlen tun:

Hier musst Du Deine installierte PHP Version kennen:

Zum Schluss musst Du noch kurz den Apache Server neuladen:

Du startest nun mit den Einträgen in der „phpunit.xml“. Ergänze die nachfolgenden Einträge in den „php“-Knoten:

Als nächstes generierst Du mit Hilfe von Artisan das Produkt Model und die zugehörige Datenbank Migrationsdatei. Der Konsolenbefehl dazu lautet wie folgt:

Durch den Parameter „-m“ wird die Migration angelegt. Das Produkt wird sehr einfach aufgebaut sein, um die Komplexität in diesem Artikel gering zu halten. Du ergänzt gleich in der Migration die Spalten: Titel (string), Preis (decimal) und Anzahl (integer). Die erstellte Migration findest Du im Verzeichnis „database/migrations/“ und sie sollte einen ähnlichen Dateinamen wie folgenden tragen „2017_10_31_111518_create_products_table.php“. Mit den Spalten sollte Deine Migrationsdatei wie folgt aussehen:

Nach dem Du die Migrationsdatei befüllt hast, solltest Du nun die „fillable“ Eigenschaften im Model hinterlegen. Dazu öffnest Du das Model „Product.php“ im Verzeichnis „app“ und fügst folgende Variable ein:

In den Unit Tests musst Du später die Produkte „mocken“ oder „faken“. Dafür bringt Laravel eine „Faker“ Library mit. Diese Library benötigt eine „Factory“ zu dem Model Produkt, damit sie die richtigen Inhalte anlegen kann. Eine Factory für das Produkt legst Du über folgen Befehl an:

Artisan hat nun für Dich die Factory „ProductFactory.php“ unter „database/factories“ erstellt. Diese öffnest Du nun und fügst folgende „return“ Anweisung hinzu:

Jetzt bist Du soweit, dass Du den Unit Test anlegen kannst. Wie im ersten Teil dieses Beitrages, hilft Dir nun wieder Artisan:

Im Unit Test „ProductTest.php“ fügst Du nun die beiden Namespaces „App\Product“ und „Illuminate\Foundation\Testing\DatabaseMigrations“ hinzu und ergänzt zu Beginn der Klasse „use DatabaseMigrations;“ um die Datenbank Migrationen durchzuführen. Dadurch kannst Du nun in der SQLite Datenbank die in Deinem Hauptspeicher läuft Datenbankoperationen durchführen und so tun, als würdest Du auf der produktiven Datenbank arbeiten.
Danach legst Du den Unit Test „test_product_can_be_created“ als Funktion an und „fakest“ mit der zuvor erstellten Factory ein Produkt, dass direkt im Anschluss per „create“ in der SQLite Datenbank gespeichert wird.
Zu guter Letzt prüfst Du per „assertDatabaseHas“, ob das erstellte Produkt auch in der Datenbank gespeichert wurde.
Deine Unit Test Sammlung sollte nun wie folgt aussehen:

Den Unit Test führt Du nun mit $ phpunit aus, wie ich es Dir zu Begin des Artikels gezeigt habe.
Sollten hier nun Fehler auftreten, wie bspw. „Illuminate\Database\QueryException: could not find driver (SQL: PRAGMA writable_schema = 1;)“, dann hast Du vermutlich vergessen SQLite3 und/oder die PHP Extension zu SQLite3 zu installieren. Weiter oben findest Du drei Befehle zur installation unter Linux. Weitere vorkompilierte Binaries findest Du unter „https://www.sqlite.org/download.html“.
Um nun noch den Fall zu testen, dass auch Produkte gekauft werden können, legst Du den passenden Produkt Controller über Artisan an:

Zuerst fügst Du im im Controller wieder den Namespace „App\Product“ hinzu und im Anschluss erstellst Du die Funktion „buy_product“ mit den Parametern „id“ und „quantity“:

Damit Du die Funktion „buy_product“ aufrufen kannst, musst Du die Route konfigurieren. Öffne dazu die Datei „web.php“ im Verzeichnis „routes“. Dort ergänzt Du folgende Route:

Integriert wird hier eine Route die mit „/products/“ beginnt, danach muss eine Produkt ID übergeben werden. Im Anschluss folgt die Route „/buy/“ und die Anzahl der Produkte die gekauft werden sollen. Wird diese Route über HTTP Post aufgerufen wird die Funktion „buy_product“ im ProductController ausgeführt und die in der URL übergebenen Parameter an die Funktion übergeben.
Jetzt kannst Du für die folgenden Scenarien Test Funktionen anlegen, um den kompletten Kaufprozess und alle Möglichen Code Pfade zu Prüfen:

  • Das Produkt kann gekauft werden und der Warenbestand verringert sich
  • Das Produkt in der URL existiert nicht
  • Bei einem leeren Warenbestand kann das Produkt nicht gekauft werden
  • Es wurde keine Anzahl in der URL übergeben, obwohl mindestens ein Produkt gekauft werden muss

Diese drei Scenarien könnten wie folgt getestet werden:

Nun hast Du über Unit Tests das Produkt Model und den Produkt Controller erfolgreich getestet und alle Code Pfade im Controller wurden mit den Tests „abgelaufen“. Als nächstes zeige ich Dir, wie Du einen Code Coverage Report zu Deinen PHPUnit Unit Tests im Laravel Projekt automatisch erstellen lassen kannst.

PHPUnit Code Coverage Report für Unit Tests in Laravel

Die Gründe Code Coverage Reports zu erzeugen sind vielfältig. Sie können für sich betrachtet werden um manuell zu prüfen, wie gut die Tesstabdeckung des eigenen Projektes ist. Ein weiterer Grund könnte die Integration in einen Build-Prozess darstellen.
PHPUnit liefert von Haus aus die Möglichkeit, Code Coverage Reports zu erzeugen. Das wird, wie alles andere auch, in der „phpunit.xml“ konfiguriert. Füge dazu am Ende der „phpunit.xml“ einfach folgenden Knoten an:

Durch den „log“ Eintrag im „logging“ Knoten wird nach Abschluss der Tests eine HTML Struktur im Verzeichnis „/report_code-coverage“ erzeugt. Die Grenzen für schlecht und gut getesten Code lassen sich mit „lowUpperBound“ und „highLowerBound“ festlegen. Eine mehr Infos findest Du in der offiziellen Dokumentation von PHPUnit. Informationen zum Logging findest Du im Unterpunkt „Logging“ unter „https://phpunit.de/manual/6.4/en/appendixes.configuration.html
Das Ergebnis Deines Produkt Controllers nach dem Ausführen der Tests sieht folgendermaßen aus:
Schritt eins im Code Coverage Report: Auswahl des Verzeichnis http
Schritt zwei im Code Coverage Report: Auswahl der Datei ProductController.php
Schritt drei im Code Coverage Report: Analyse der Datei ProductController.php
Du hast nun die grundlegenden Werkzeuge für das Unit Testing in Laravel 5.5 an der Hand. Du hast gelernt, wie Du Deine „phpunit.xml“ erweitern kannst, wie Du eine Testdatenbank mit SQLite3 einrichtest und wie Du Tests für Models und Controller erstellst. Zum Schluss hast Du noch die automatische Generierung von Code Coverage Reports aktiviert.

Mögliche Fehler beim Ausführen der PHPUnit Unit Tests in Laravel

Anbei folgt eine Liste möglicher Fehler die beim Unit Testing mit PHPUnit unter Laravel 5.5 auftreten können. Du kannst dabei helfen, diese Liste zu erweitern in dem Du von Deinen Fehlern berichtest.

Fehler 1 – Expected status code 200 but received 404

Beim Ausführen Deiner HTTP – Unit Tests (get / call) tritt folgender Fehler auf:

Mögliche Lösung:
Du hast für Dein Laravel-Projekt einen „virtual host“ / „vhost“ Eintrag angelegt, damit Du Deine Website über eine „richte“ URL erreichen kannst: „http://mein-projekt.dev“.
In diesem Fall musst Du in der „phpunit.xml“ den folgenden Environment Eintrag ergänzen:

 

About The Author

Britta Schwab

Hallo, ich bin Britta, Gründerin von Pixelwerker. Ich liebe das Internet, Onlinemarketing und viel grünen Tee. Mich begeistert Webdesign, SEO und ich liebe unsere Werbeagentur in Kassel!

Leave a reply

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Keine Artikel mehr verpassen

Keine Artikel mehr verpassen

Willst du auf dem Laufenden bleiben? Wir schreiben dir gern, wenn es Updates gibt.

Trag dich einfach in unseren kostenlosen Newsletter ein!

 

Und keine Sorge: wir hassen Spam. Du bekommst von uns garantiert keinen. Ehrenwort!

Erfolgreich eingetragen!