Akzeptanztests in PHP - Mit Codeception ein Kinderspiel
11. Juli 2013 Softwaretest von Eric Kubenka
Nachdem ich mich in den vergangenen Wochen mit den Themen, TDD, PHPUnit, Mockery und Co. auseinandergesetzt habe und meine Erfahrungen hier kurz präsentierte, kann ich nun den nächsten Punkt auf meiner ToDo-Liste abhaken. Einbinden und Nutzung von Codeception.
Codeception ist ein Testframework für PHP und liefert neben zahlreichen Helfern für funktionale Tests und Unit-Tests auch ausgesprochen hilfreiche Methoden für die Akzeptanztests - also die Tests, welche dem wirklichen Verhalten der Endanwender am ähnlichsten sind.
Folgend möchte kurz die Einbindung, Installation und Verwendung für Akzeptanztests (Oberflächentests) mithilfe von Codeception erläutern, ohne dabei auch nur ein mal den Browser geöffnet zu haben und trotzdem zu validieren, dass die Oberflächenfunktionen erfolgreich ihren Dienst erfüllen.
Die Installation
Als schnellste und bequemste Art und Weise Codeception in das bestehende oder geplante Projekt zu integrieren sehe ich Composer. Mit folgender Datei werden sowohl Codception, als auch Mockery und PHPUnit in das Projekt einbezogen. Heut soll es aber nur um Codeception gehen.
// composer.json { "name": "codefever/codeceptionexample", "description": "", "authors": [ { "name": "Eric Kubenka", "email": "info@code-fever.de" } ], "require": { "php": ">=5.3.0" }, "require-dev": { "phpunit/phpunit": "3.7.*", "mockery/mockery": "dev-master", "codeception/codeception": "1.6.1.1" }, "autoload": { "classmap": [ "src", "tests" ] }, "minimum-stability": "dev" }
Nachdem composer install --dev ausgeführt wurde, folgt die Installation des Frameworks. Dazu muss in der Befehlszeile vom Projektroot ausgehend folgender Befehl aufgerufen werden.
vendor/bin/codecept bootstrap
Nach erfolgreicher Konfiguration sieht die Ordner-Struktur wie folgt aus.
Nun müssen noch der Basis-Url-Parameter für die Akzeptanztests angepasst werden. Diese Veränderung wird logischerweise in der acceptance.suite.yml-Datei vorgenommen. Da mein Blog die Basis bildet, wird dort die volle URL eingetragen.
class_name: WebGuy modules: enabled: - PhpBrowser - WebHelper config: PhpBrowser: url: 'http://code-fever.de/'
Die Aufgabe
Als Aufgabe für die folgende Einführung steht folgendes zu Buche: Navigieren Sie auf die Seite http://code-fever.de und überprüfen Sie, dass eine Schaltfläche mit der Aufschrift kontakt angezeigt wird. Anschließend klicken Sie auf die Schaltfläche, überprüfen die URL auf Richtigkeit und füllen das Kontaktformular mit Dummy-Daten aus. In das Feld für die Sicherheitsabfrage geben Sie einen Dummy-Wert ein und klicken auf die Schaltfläche Absenden. Abschließen überprüfen Sie die Anzeige der Fehlermeldung Bitte beantworten Sie die Sicherheitsfrage.
Das Vorgehen
Um die Aufgabenstellung zu realisieren muss zuerst ein neuer Testfall angelegt werden. Über die Eingabeaufforderung ist dies mit folgender Zeile möglich.
vendor/bin/codecept generate:cest acceptance Codefever
Der nun generierte Testfall CodefeverCest wird im Verzeichnis tests/acceptance/ abgelegt und gestaltet sich standardmäßig so.
<?php class CodefeverCest { public function _before() { } public function _after() { } // tests public function tryToTest(\WebGuy $I) { } }
Um Euch direkt auf die meiner Meinung nach sehr gelungene Syntax von Codeception aufmerksam zu machen, habe ich folgend direkt die Schritte des Aufrufens der Webseite und das Navigieren zur Kontaktseite implementiert.
<?php // CodefeverCest.php public function testSendContactFormWithWrongSecurityAnswerShowsError(\WebGuy $I) { $I->am('Visitor'); $I->wantTo('navigate to contact area and send a request with wrong security number'); $I->lookForwardTo('get an error'); // Open code-fever.de $I->amOnPage(''); // Assert that i'm on code-fever.de/ $I->seeCurrentUrlEquals('/'); // Assert that there is a link with 'kontakt' $I->seeLink('kontakt'); // Click that link $I->click('kontakt'); // Assert that current url is now code-fever.de/kontakt.html $I->seeCurrentUrlEquals('/kontakt.html'); }
Ich hoffe jedem von Euch wird nun klar, wie genial das eigentlich ist. Ließt man nur die Wörter der Methoden wird sofort deutlich, was der Tests eigentlich ausführt und letztendlich testet. So wird auch Nicht-Entwicklern mit ein, zwei Blicken sofort vor Augen geführt, dass ein bestimmtes Verhalten erfolgreich getestet wird.
Verhaltensgetrieben Software-Entwicklung, oder auch Behaviour Driven Development, kurz BDD, beschreibt die Anforderungen an Softwareprodukt textuell. Dabei wird das erwartete Verhalten der Anwendung so beschrieben, dass es problem- und nahtlos jederzeit automatisiert werden kann.
Um sicherzugehen, ob dir aktuell geschriebene Testfall bereits funktioniert, wird der Testfall mittels folgender Befehlszeile zur Ausführung gebracht. Achtet auf das Schlüsselwort acceptance, damit auch wirklich die Akzeptanz-Tests ausgeführt werden.
vendor/bin/codecept run acceptance
Ist Euch aufgefallen, dass kein Browser geöffnet wurde und dennoch ein Akzeptanztest durchgeführt wurden? Das ist meiner Meinung nach ein großer Vorteil von Codeception – Es lässt sich über die Eingabeaufforderung ausführen und es wird nicht unnötig auf das Öffnen des Browser gewartet. Wie das Ganze funktioniert? Codeception wertet die Antworten der Requests an die gegebene URL aus. Im Optimalfall ist dass der komplette DOM, der wird dann mittels internen Methoden geparst und schon kann sichergestellt werden, was sichergestellt werden muss – Die Funktion und das Verhalten.
Auch die schrittweise Angabe der absolvierten Testschritte, falls ein Test fehlschlägt, ist meiner Meinung nach sehr gelungen.
Damit dies auch wirklich eine Einführung bleibt, stelle ich im nächsten Code-Teil schon die gesamte Lösung vor. Falls ihr jedoch mehr Interesse dran habt das ganze zu üben, so geht doch Schritt für Schritt nach der oben notierten Aufgabe vor und vergleicht anschließend nur noch die Lösungen.
<?php // CodefeverCest.php public function testSendContactFormWithWrongSecurityAnswerShowsError(\WebGuy $I) { $I->am('Visitor'); $I->wantTo('navigate to contact area and send a request with wrong security number'); $I->lookForwardTo('get an error'); // Open code-fever.de $I->amOnPage(''); // Assert that i'm on code-fever.de/ $I->seeCurrentUrlEquals('/'); // Assert that there is a link with 'kontakt' $I->seeLink('kontakt'); // Click that link $I->click('kontakt'); // Assert that current url is now code-fever.de/kontakt.html $I->seeCurrentUrlEquals('/kontakt.html'); # second part - validate that an error is shown // Fill fields by name $I->fillField('name', 'codeception WebGuy'); $I->fillField('email', 'codeception@code-fever.de'); $I->fillField('subject', 'Codception is cool'); $I->fillField('message', 'This is a dummy contact request using your tutorial'); // Fill field by label $I->fillField('Sicherheitsfrage', '4000'); // Click button 'Absenden' $I->click('Absenden'); // Assert that Url is still /kontakt.html $I->seeCurrentUrlEquals('/kontakt.html'); // Assert that the error is displayed $I->see('Bitte beantworten Sie die Sicherheitsfrage!'); }
Fazit
Meiner Meinung nach ist Codeception ein gelungenes Framework, welches durch einfache und doch elegante Syntax und Anwendung überzeugt. Natürlich war dies wie immer nur ein Einblick und Codeception bietet neben den durchgeführten Akzeptanztests auch Helfer für Unit- und funktionale Tests. Die umfangreiche Dokumentation findet ihr hier.
Natürlich lässt sich das oben angesprochene BDD einfach mit dem TDD kombinieren und so lassen sich zukünftige Projekte von Euch noch einfacher entwickeln – Einfach aus dem Grund, weil man bereits vor dem Schreiben der ersten Produktiv-Code-Zeile das Verhalten der zukünftigen Anwendung beschrieben hat und der Test dafür bereist entwickelt wurde. Ein Nachdenken über das Anwendungsverhalten während der Entwicklung ist also nicht mehr nötig.
In diesem Sinne Happy Coding. SourceCode wie immer auf GitHub.