Florian Herlings, freier Webentwickler aus Düsseldorf.

Einführung in Integrations-Tests in PHP

Denkt man nicht bereits beim initialen Entwurf einer PHP-Applikation an vernünftiges Testing, kann es im Nachhinein sehr schwierig werden eine Qualitätskontrolle auf diese Weise einzuführen.

Der erste Schritt, den man gehen kann um Testing im Nachhinein einzubringen, können Integrationstests sein. Diese Art von Tests testen nicht ein Teilstück des Systems (wie zum Beispiel eine Funktion oder Klasse), sondern das ganze System, so wie es eingesetzt wird. Ein Beispiel eines solchen Tests könnte so formuliert werden: Wenn ich auf die Startseite gehe, erwarte ich dass dort ein Login-Link ist. Wenn ich diesen klicke, soll ich auf einer Seite landen auf der ein Formular ist.

Dieser Artikel soll am Beispiel darstellen, wie man solche Integrations-Tests mit PHP schreibt. Genutzt werden soll die freie Bibliothek Mink, die aus dem Behat-Projekt (unten mehr) hervorgegangen ist. Um eine problemlose Integration in IDEs (wie Eclipse oder NetBeans) und CI-Systeme (wie Jenkins) zu erlauben, wird Mink mit PHPUnit gepaart.

Setup von PHPUnit und Mink

Zuerst muss für PHPUnit eine Konfigurations-Datei angelegt werden, die PHPUnit mitteilt, was zu tun ist. Diese Datei enthält in unserem Fall nur die Antworten auf zwei Kern-Fragen: Wo liegen die Tests? und Wo liegt die Bootstrap-Datei?

phpunit.xml
<phpunit bootstrap="bootstrap.php">
  <testsuite name="Integration-Tests">
    <directory>./Integration/</directory>
  </testsuite>
</phpunit>

Die Bootstrap-Datei enthält Code, der ausgeführt werden soll bevor die Tests laufen. Sie sorgt also dafür, dass die gesamte Infrastruktur, auf die die Tests aufbauen vorhanden ist.

Für die Bootstrap-Datei benötigt man zunächst die Mink-Bibliothek (vorzugsweise als .phar-Datei). Diese Bibliothek ist in der Lage einen Browser zu simulieren und ermöglicht dadurch erst die Integrations-Tests. Die Bibliothek kann direkt von der Mink-Webseite heruntergeladen werden.

Darauf setzt man eine Konstante mit der BASE_URL (um den Test-Code etwas zu vereinfachen) und eine Klasse, die von PHPUnit_Framework_TestCase erbt. Diese Klasse initialisiert nur die Mink-Bibliothek und startet eine Browser-Session. Alle Integrations-Tests erben dann von der Klasse und können auf die Browser-Session zugreifen.

bootstrap.php
<?php
 
require_once 'mink.phar';
define('BASE_URL', 'http://www.florianherlings.de/');
 
class MinkTestCase extends PHPUnit_Framework_TestCase
{
  function setUp()
  {
    $this->driver = new \Behat\Mink\Driver\GoutteDriver();
    $this->session = new \Behat\Mink\Session($this->driver);
    $this->session->start();
  }
 
  function tearDown()
  {
    $this->session->stop();
  }
}

Tests schreiben

Darauf können die eigentlichen Tests geschrieben werden. Jede Test-Klasse muss in das Integration-Verzeichnis gelegt werden und genau so heißen, wie ihr Dateiname (vgl. Beispiel unten). PHPUnit nimmt an, dass jede Methode der Klasse, die mit test beginnt ein Test ist und führt diesen aus. Im Beispiel unten kann man einen Test sehen, der auf die vorher definierte Seite BASE_URL (siehe oben) geht, dort ein Element mit der ID logo sucht und prüft ob das Element existiert. Des Weiteren wird getestet, ob das Logo auf die Startseite verlinkt.

Integration/HomepageTest.php
<?php
 
class HomepageTest extends MinkTestCase
{
  function testHomepageHasLogo()
  {
    $this->session->visit(BASE_URL);
    $page = $this->session->getPage();
 
    $logo = $page->find('css', '#logo');
    $this->assertNotNull($logo);
 
    $logoHref = $logo->getAttribute('href');
    $this->assertEquals($logoHref, BASE_URL);
  }
}

Um die Tests laufen zu lassen, muss zunächst sicher gestellt sein, dass PHPUnit installiert ist. Dies kann auf einfach Weise über PEAR gemacht werden. Danach begibt man sich mit der Kommandozeile in den Ordner in dem die Datei phpunit.xml liegt und führt den folgenden Befehl aus:

> phpunit

Die Ausgabe sollte wie folgt aussehen:

PHPUnit 3.7.8 by Sebastian Bergmann.
Configuration read from /path/to/your/phpunit.xml
..
Time: 2 seconds, Memory: 7.75Mb
OK (1 test, 2 assertions)

Auf diese Weise kann man ohne etwas am eigentlichen Code zu verändern das gesamte System testen. Dies eignet sich nicht nur für komplizierte Legacy-Anwendungen, sondern auch für Webseiten, die mit CMS (wie Wordpress oder Drupal) umgesetzt wurden.

Weiterführende Optionen

Wer hier weiter gehen will, dem bieten sich zwei interessante Optionen: Auf der einen Seite kann man das Formulieren der Test-Fälle nicht nur mit PHP durchführen, sondern hat auch die Möglichkeit diese mit „normalem Text“ zu formulieren. Dies ist durch das Behat-Projekt möglich, aus dem Mink entstanden ist. Dieser, „Behavior Driven Development“ genannte Vorgang ist besonders interessant, um Nicht-Programmierer in das Testen zu involvieren. Es ist sinnvoll sich hierüber in der Behat-Dokumentation zu informieren.

Darüber hinaus gibt es nicht nur bei der Formulierung, sondern auch bei der Durchführung von Tests noch eine interessante Option. In unserer bootstrap.php-Datei wird die Bibliothek mit dem so genannten GoutteDriver initialisiert. Dies wiederum sorgt dafür, dass alle Tests von einem simulierten Browser auf der Kommandozeile durchgeführt wird. Es kommt jedoch häufig vor, dass man kompliziertere Vorgänge in Javascript testen muss, was über die Kommandozeilen-Option nicht möglich ist. Doch Mink hat auch hierfür eine schöne Lösung: Statt auf den GoutteDriver zu setzen, kann man problemlos einen echten Browser fernsteuern und sichergehen, dass alle Funktionen auch wie gewollt zum Beispiel im Firefox funktionieren. Hierzu sollte man sich noch einmal separat die Mink-Dokumentation ansehen.



Lerne mehr auf CodeScouts.de