Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. PHP

Testen wie ein Boss in Laravel: Modelle

by
Difficulty:AdvancedLength:LongLanguages:

German (Deutsch) translation by Valentina (you can also view the original English article)

Wenn Sie erfahren möchten, warum Tests von Vorteil sind, ist dies nicht der richtige Artikel für Sie. Im Verlauf dieses Tutorials gehe ich davon aus, dass Sie die Vorteile bereits verstehen und hoffen, zu lernen, wie Sie Ihre Tests in Laravel 4 am besten schreiben und organisieren können.

Version 4 von Laravel bietet im Vergleich zu seiner vorherigen Version ernsthafte Verbesserungen in Bezug auf Tests. Dies ist der erste Artikel einer Reihe, in dem beschrieben wird, wie Tests für Laravel 4-Anwendungen geschrieben werden. Wir beginnen die Serie mit der Erörterung von Modelltests.


Einstellung

In-Memory-Datenbank

Sofern Sie keine Rohabfragen in Ihrer Datenbank ausführen, ermöglicht Laravel Ihrer Anwendung, datenbankunabhängig zu bleiben. Mit einem einfachen Treiberwechsel kann Ihre Anwendung jetzt mit anderen DBMS (MySQL, PostgreSQL, SQLite usw.) arbeiten. Unter den Standardoptionen bietet SQLite eine besondere, aber sehr nützliche Funktion: In-Memory-Datenbanken.

Mit Sqlite können wir die Datenbankverbindung auf :memory: setzen, was unsere Tests drastisch beschleunigt, da die Datenbank nicht auf der Festplatte vorhanden ist. Darüber hinaus wird die Produktions- /Entwicklungsdatenbank niemals mit verbleibenden Testdaten gefüllt, da die Verbindung :memory: immer mit einer leeren Datenbank beginnt.

Kurz gesagt: Eine In-Memory-Datenbank ermöglicht schnelle und saubere Tests.

Erstellen Sie im Verzeichnis app/config/testing eine neue Datei mit dem Namen database.php und füllen Sie sie mit folgendem Inhalt:

Die Tatsache, dass database.php im Konfiguration-testing-Verzeichnis abgelegt ist, bedeutet, dass diese Einstellungen nur in einer Testumgebung verwendet werden (die Laravel automatisch festlegt). Wenn auf Ihre Anwendung normal zugegriffen wird, wird die speicherinterne Datenbank daher nicht verwendet.

Vor dem Ausführen von Tests

Da die In-Memory-Datenbank beim Herstellen einer Verbindung immer leer ist, ist es wichtig, die Datenbank vor jedem Test zu migrieren. Öffnen Sie dazu app/tests/TestCase.php und fügen Sie am Ende der Klasse die folgende Methode hinzu:

HINWEIS: Die setUp()-Methode wird vor jedem Test von PHPUnit ausgeführt.

Diese Methode bereitet die Datenbank vor und ändert den Status der Mailer-Klasse von Laravel, um dies pretend. Auf diese Weise sendet der Mailer beim Ausführen von Tests keine echte E-Mail. Stattdessen werden die "gesendeten" Nachrichten protokolliert.

Um app/tests/TestCase.php abzuschließen, rufen Sie prepareForTests() innerhalb der PHPUnit setUp()-Methode auf, die vor jedem Test ausgeführt wird.

Vergessen Sie nicht parent::setUp(), da wir die Methode der übergeordneten Klasse überschreiben.

Zu diesem Zeitpunkt sollte app/tests/TestCase.php wie folgt aussehen. Denken Sie daran, dass createApplication automatisch von Laravel erstellt wird. Sie müssen sich keine Sorgen machen.

Um unsere Tests zu schreiben, erweitern Sie einfach TestCase. Die Datenbank wird vor jedem Test initialisiert und migriert.


Die Tests

Es ist richtig zu sagen, dass wir in diesem Artikel den TDD-Prozess nicht verfolgen werden. Das Problem hier ist didaktisch, mit dem Ziel zu demonstrieren, wie die Tests geschrieben werden können. Aus diesem Grund habe ich mich entschlossen, zuerst die fraglichen Modelle und dann die zugehörigen Tests zu enthüllen. Ich glaube, dass dies ein besserer Weg ist, um dieses Tutorial zu veranschaulichen.

Der Kontext dieser Demo-Anwendung ist ein einfaches Blog/CMS, das Benutzer(Authentifizierung), Beiträge und statische Seiten enthält (die im Menü angezeigt werden).

Postmodell

Bitte beachten Sie, dass das Modell die Klasse Ardent und nicht Eloquent erweitert. Ardent ist ein Paket, das eine einfache Validierung beim Speichern des Modells ermöglicht (siehe die Eigenschaft $rules).

Als nächstes haben wir das public static $factory-Array, das das FactoryMuff-Paket nutzt, um die Objekterstellung beim Testen zu unterstützen.

Sowohl Ardentx als auch FactoryMuff sind über Packagist und Composer erhältlich.

In unserem Post-Modell haben wir über die Magic-Author-Methode eine Beziehung zum User-Modell.

Schließlich haben wir eine einfache Methode, die das Datum zurückgibt und als "day/month/year" formatiert ist.

Post-Tests

Um die Organisation zu gewährleisten, habe ich die Klasse mit den Post-Modelltests in app/tests/models/PostTest.php platziert. Wir werden alle Tests abschnittsweise durchgehen.

Wir erweitern die TestCase-Klasse, die für PHPUnit-Tests in Laravel erforderlich ist. Vergessen Sie auch nicht unsere prepareTests-Methode, die vor jedem Test ausgeführt wird.

Dieser Test ist "optional". Wir testen, ob die Beziehung "Post gehört zum User". Der Zweck hier ist hauptsächlich, die Funktionalität von FactoryMuff zu demonstrieren.

Sobald die Post-Klasse über das statische Array $factory verfügt, das 'author_id' => 'factory| User' enthält (beachten Sie den oben gezeigten Quellcode des Modells), instanziiert FactoryMuff einen neuen User, füllt seine Attribute, speichert ihn in der Datenbank und kehrt schließlich zurück seine ID für das Attribut author_id im Post.

Damit dies möglich ist, muss das User-Modell über ein $factory-Array verfügen, das auch seine Felder beschreibt.

Beachten Sie, wie Sie über $post->author auf die User-Beziehung zugreifen können. Als Beispiel können wir auf den $post->author->username oder ein anderes vorhandenes Benutzerattribut zugreifen.

Das FactoryMuff-Paket ermöglicht die schnelle Instanziierung konsistenter Objekte zum Testen, während alle erforderlichen Beziehungen berücksichtigt und instanziiert werden. In diesem Fall wird User beim Erstellen eines Posts mit FactoryMuff::create('Post') ebenfalls vorbereitet und verfügbar gemacht.

Zum Abschluss bestimmen wir, ob die von der Methode postedAt() zurückgegebene Zeichenfolge dem Format "Tag / Monat / Jahr" entspricht. Für eine solche Überprüfung wird ein regulärer Ausdruck verwendet, um zu testen, ob das Muster \d{2}\/\d{2}\/\d{4} ("2 Zahlen" + "Balken" + "2 Zahlen" + "Balken)" + "4 Zahlen") wird gefunden.

Alternativ könnten wir den assertRegExp-Matcher von PHPUnit verwenden.

Zu diesem Zeitpunkt lautet die Datei app/tests/models/PostTest.php wie folgt:

PS: Ich habe mich entschieden, den Namen der Tests aus Gründen der Lesbarkeit nicht in CamelCase zu schreiben. PSR-1 vergib mir, aber testRelationWithAuthor ist nicht so lesbar, wie ich es persönlich vorziehen würde. Natürlich können Sie den Stil verwenden, den Sie am meisten bevorzugen.

Seitenmodell

Unser CMS benötigt ein Modell zur Darstellung statischer Seiten. Dieses Modell wird wie folgt implementiert:

Wir können beobachten, dass die statische Methode renderMenu() eine Reihe von Links für alle vorhandenen Seiten rendert. Dieser Wert wird im Cache-Schlüssel 'pages_for_menu' gespeichert. Auf diese Weise muss bei zukünftigen Aufrufen von renderMenu() nicht mehr auf die reale Datenbank zugegriffen werden. Dies kann die Leistung unserer Anwendung erheblich verbessern.

Wenn jedoch eine Page gespeichert oder gelöscht wird (afterSave()- und delete()-Methoden), wird der Wert des Caches gelöscht, sodass renderMenu() den neuen Status der Datenbank widerspiegelt. Wenn also der Name einer Seite geändert oder gelöscht wird, wird der key 'pages_for_menu' aus dem Cache gelöscht. (Cache::forget('pages_for_menu');)

HINWEIS: Die Methode afterSave() ist über das Ardent-Paket verfügbar. Andernfalls müsste die Methode save() implementiert werden, um den Cache zu bereinigen und parent::save() aufzurufen.

Seitentests

In: app/tests/models/PageTest.php schreiben wir die folgenden Tests:

Wir haben wieder einen "optionalen" Test, um die Beziehung zu bestätigen. Da Beziehungen in der Verantwortung von Illuminate\Database\Eloquent liegen, das bereits von Laravels eigenen Tests abgedeckt wird, müssen wir keinen weiteren Test schreiben, um zu bestätigen, dass dieser Code wie erwartet funktioniert.

Dies ist einer der wichtigsten Tests für das Page-Modell. Zunächst werden vier Seiten in der for-Schleife erstellt. Anschließend wird das Ergebnis des Aufrufs renderMenu() in der $result-Variablen gespeichert. Diese Variable sollte eine HTML-Zeichenfolge enthalten, die Links zu den vorhandenen Seiten enthält.

Die foreach-Schleife prüft, ob der Slug (URL) jeder Seite in $result vorhanden ist. Dies ist ausreichend, da das genaue Format des HTML für unsere Anforderungen nicht relevant ist.

Schließlich stellen wir fest, ob im Cache-Schlüssel pages_for_menu etwas gespeichert ist. Mit anderen Worten, hat der Aufruf von renderMenu() tatsächlich einen Wert im Cache gespeichert?

Mit diesem Test soll überprüft werden, ob beim Speichern einer neuen Page der Cache-Schlüssel 'pages_for_menu' geleert wird. Der FactoryMuff::create('Page'); löst schließlich die save()-Methode aus, sodass ausreichen sollte, damit der Schlüssel 'pages_for_menu' gelöscht wird.

Ähnlich wie beim vorherigen Test wird hierdurch festgestellt, ob der Schlüssel 'pages_for_menu' nach dem Löschen einer Page ordnungsgemäß geleert wird.

Ihre PageTest.php sollte folgendermaßen aussehen:

Benutzermodell

In Bezug auf die zuvor vorgestellten Modelle haben wir jetzt den User. Hier ist der Code für dieses Modell:

Dieses Modell fehlt an Tests.

Wir können beobachten, dass es mit Ausnahme von Beziehungen (die zum Testen hilfreich sein können) hier keine Methodenimplementierung gibt. Was ist mit der Authentifizierung? Nun, die Verwendung des Confide-Pakets bietet bereits die Implementierung und Tests dafür.

Die Tests für Zizaco\Confide\ConfideUser befinden sich in ConfideUserTest.php.

Es ist wichtig, die Klassenverantwortung zu bestimmen, bevor Sie Ihre Tests schreiben. Das Testen der Option zum "Zurücksetzen des Kennworts" eines Users wäre überflüssig. Dies liegt daran, dass die ordnungsgemäße Verantwortung für diesen Test in Zizaco\Confide\ConfideUser liegt; nicht im User.

Gleiches gilt für Datenvalidierungstests. Da das Paket Ardent diese Verantwortung übernimmt, wäre es nicht sinnvoll, die Funktionalität erneut zu testen.

Kurz gesagt: Halten Sie Ihre Tests sauber und organisiert. Bestimmen Sie die ordnungsgemäße Verantwortung jeder Klasse und testen Sie nur, wofür sie ausschließlich verantwortlich ist.


Abschluss

Running Tests

Die Verwendung einer In-Memory-Datenbank ist eine gute Vorgehensweise, um Tests für eine Datenbank schnell auszuführen. Dank der Hilfe einiger Pakete wie Ardent, FactoryMuff und Confide können Sie die Codemenge in Ihren Modellen minimieren und gleichzeitig die Tests sauber und objektiv halten.

In der Fortsetzung dieses Artikels werden wir die Controller-Tests überprüfen. Bleib dran!

Beginnen wir noch mit Laravel 4 und lassen Sie sich das Wesentliche beibringen!

Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.