PHPUnit ist ein klassisches Unit-Testing-Framework wie JUnit für Java oder NUnit im dotNet-Bereich. Darüber hinaus gibt es aber die Möglichkeit PHPUnit mit Selenium zu verheiraten. Das eröffnet natürlich ganz neue Dimensionen bei der automatisierten Qualitätssicherung von Webanwendungen.
Selenium-Skripte als PHPunit-Tests exportieren
Selenium-Skripte können als PHPUnit-Tests exportiert werden. Diese Unittests lassen sich natürlich nicht in der Selenium-IDE abspielen,
die nur Selenese versteht. Aber es gibt eine ganze Reihe andere Anwendungsmöglichkeiten die da zum Beispiel wären:
Seleniumtests aus der IDE (Eclipse / Netbeans) ausführen, Seleniumtests dynamisch gestalten und vieles mehr.
Export durchführen
Der Export eines Selenese-Tests in einen PHPUnit-Test erfolgt in der Selenium-IDE im Browser. Dazu wird ein extra Plugin benötigt. Dann kann jeder einzelne Test wie folgt exportiert werden:
PHPUnit-Selenium
Das Resultat ist einfacher PHPUnittest der die entsprechenden Selenese-Befehle ausführt. Ein einfacher Selenese-Testcase, der ein Login-Formular ausfüllt, abschickt und dann wartet bis der Text „Menu“ geladen ist sieht etwa so aus:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head profile="http://selenium-ide.openqa.org/profiles/test-case">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="selenium.base" href="http://localhost/" />
<title>Login</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Login</td></tr>
</thead><tbody>
<tr>
<td>open</td>
<td>/</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>name=login</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>name=pwd</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>name=login</td>
<td>testbenutzer</td>
</tr>
<tr>
<td>type</td>
<td>name=pwd</td>
<td>testpasswort</td>
</tr>
<tr>
<td>click</td>
<td>//button[contains(text(),'Login')]</td>
<td></td>
</tr>
<tr>
<td>waitForTextPresent</td>
<td>Menu</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
Exportiert in PHPUnit sieht es etwa so aus:
<?php
class Example extends PHPUnit_Extensions_SeleniumTestCase
{
protected function setUp()
{
$this->setBrowser("*firefox");
$this->setBrowserUrl("http://localhost/");
}
public function testMyTestCase()
{
$this->open("/");
for ($second = 0; ; $second++) {
if ($second >= 60) $this->fail("timeout");
try {
if ($this->isElementPresent("name=login")) break;
} catch (Exception $e) {}
sleep(1);
}
for ($second = 0; ; $second++) {
if ($second >= 60) $this->fail("timeout");
try {
if ($this->isElementPresent("name=pwd")) break;
} catch (Exception $e) {}
sleep(1);
}
$this->type("name=login", "testbenutzer");
$this->type("name=i_form[pwd]", "testpasswort");
$this->click("//button[contains(text(),'Login')]");
for ($second = 0; ; $second++) {
if ($second >= 60) $this->fail("timeout");
try {
if ($this->isTextPresent("Menu")) break;
} catch (Exception $e) {}
sleep(1);
}
}
}
?>
Vorteile
Am PHP-Quelltext ist es gut zu sehen, die Tests können dynamisiert werden. In PHP können sich die Tests abhängig von bestimmten Bedingungen unterschiedlich verhalten, es können Datenbankaufrufe gemacht werden, Systembefehle /Shellskripte ausgeführt werden usw. wer volle Kontrolle möchte ist hier genau richtig.
Nachteile
Der nach PHP exportierte Test lässt sich nicht in der Selenium-IDE abspielen. Das impliziert auch, dass man bei Veränderungen des SUT (System under Test) Selenese-Tests aus PHPUnit direkt aufrufen Neben dem Exportieren von Selenese nach PHPUnit gibt es auch noch die Möglichkeit Selenese-Tests direkt aus PHPUnit heraus aufzurufen.
Einen bestimmten Test aufrufen
Um einen beliebigen Selenesetest an einer bestimmten Stelle aus einem PHPUnit-Test heraus aufzurufen gibt es den Befehl „runSelenese“. Anschaulich ist es immer am Beispiel:
<?php
/*
* Einbindinden der entsprechenden PHP-Unit-Extension
*/
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
/**
* Testklasse zur Demonstration
*
*/
class SeleneseTests extends PHPUnit_Extensions_SeleniumTestCase {
// Die zu testen Browser
public static $browsers = array(
array(
'name' => 'Firefox',
'browser' => '*firefox',
'host' => 'localhost',
)
);
/**
* Test setUp (PHPUnit)
*/
protected function setUp() {
$this->setBrowserUrl("http://localhost/");
}
/**
* Selenium-Test ausführen
*/
public function testMyTestCase() {
$this->runSelenese('testcase.sel');
}
}
?>
Ein komplettes Verzeichnis mit Tests auf einmal ausführen
<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
class SeleneseTests extends PHPUnit_Extensions_SeleniumTestCase
{
public static $seleneseDirectory = '/verzeichnis/mit/testskripten';
}
?>
Vergleich runSelenese vs Testdirectory
Auf den ersten Blick sieht die zweite Methode, alle mit einem Aufruf zu erledigen, sehr verlockend aus. Aber erfahrungsgemäß funktioniert es
nicht ganz so gut wie es soll. Auch fehlt hier die Möglichkeit Einfluss zu nehmen auf den Ablauf der Tests. Im Gegensatz dazu erscheint die Methode jeden einzelnen Testfall per runSelenese() aufzurufen eher umständlich. Dagegen ist diese Variante im Betrieb aber sehr stabil. Zu empfehlen ist der Mittelweg. Liest man zum Beispiel die relevanten Verzeichnisse mit PHP aus so kann unter Verwendung von Schleifen sehr leicht das Verhalten der zweiten Variante nachgebaut werden. Trotzdem bleibt die Kontrolle über jeden einzelnen Test erhalten. Es sind Laufzeitbedingungen denkbar aber auch Schemate wie der Testablauf zum beispiel durch bestimmte Dateinamensmuster der Selenese-Skript-Dateien in PHP gesteuert werden kann.