Selenium Tutorial deutsch: Testen von dynamischen Webapplikationen mit PHP und Selenium Grid
Nachdem wir die Architektur von Selenium Grid verstanden und unseren ersten Selenium Hub und Node gestartet haben ist es nun an der Zeit, das erste PHP-Testscript zu schreiben.
- Selenium und PHP testen: Testfall
- Tutorial PHP und Selenium Grid: Step by Step
- Schlusswort: Automated Website-Testing lohnt sich
Selenium Tutorial deutsch: Testfall
Das Testen unserer dynamischen Webanwendung soll folgendes beinhalten:
- Aufrufen der Startseite
- Warten, bis die Seite geladen ist
- Anklicken eines Links, welcher AJAX triggert
- Warten auf die Ausführung von AJAX
- Prüfen des Inhalts eines bestimmten Elements
- Bei fehlerhaftem Inhalt einen Screenshot erstellen
Als Testobjekt nehmen wir eine mit AJAX-lastige Seite unseres Kunden: budenheim.com. Dort werden z.B. beim Klicken auf die meisten Links nicht wie gewohnt neue Seiten geladen, sondern der Inhalt dieser Seiten via asynchronem JavaScript nachgeladen. Da können wir uns austoben!
Selenium Tutorial PHP und Selenium Grid: Step by Step
Einstellungen im PHP-Code vornehmen
In dem vorherigen Artikel wurde bereits gezeigt, wie man die für PHP nötigen Selenium-Bibliotheken installiert, um damit vernünftig arbeiten zu können. Wenn das geschehen ist, kann man diese wie folgt in sein PHP-Script einbinden:
<?php require_once ('php-webdriver/lib/__init__.php'); echo "Website-Check 1.0\n";
Und wenn wir uns schon mal im Header des Quellcodes befinden, schreiben wir gleich fest, wie unser Hub zu erreichen ist:
<?php $host = 'http://swuser-xubuntu:4444/wd/hub';
Wobei für den URL dieses Schema angewendet wird:
http://{Hub-Hostname/IP}:{Hub-Port}/wd/hub
Jetzt definieren wir einen Browser, den wir dann im Selenium Grid steuern können. Nehmen wir in unserem Beispiel Google Chrome, der auf den bereits laufenden Node zeigt.
<?php $chrome = DesiredCapabilities::chrome ( );
Das gleiche Prinzip kann man auch für andere Browser anwenden:
<?php $firefox = DesiredCapabilities::firefox ( ); $ie = DesiredCapabilities::internetExplorer ( );
Diese Angaben kann man noch etwas näher spezifizieren, um z.B. eine bestimmte Version unter einem bestimmten Betriebssystem anzusprechen:
<?php $chrome = DesiredCapabilities::chrome ( ); $chrome -> setPlatform ( 'WINDOWS' ); $chrome->setVersion('40.0');
Die Angaben hängen direkt mit den Parametern im Ausführungsbefehl des Nodes zusammen. Wenn man einen Selenium Node mit Google Chrome wie folgt gestartet hat …
java -jar C:/selenium/selenium-server-standalone-2.44.0.jar \ -role webdriver \ -hub http://swuser-xubuntu:4444/grid/register \ -browser browserName=chrome,maxInstances=4,*****platform=WINDOWS,version=40.0***** \ -Dwebdriver.*****chrome*****.driver=C:/selenium/chromedriver.exe \ -port 5556 # man beachte die mit ***** hervorgehobenen Stellen
… kann man genau diesen Node dadurch gezielt ansprechen, indem man folgende Angaben macht:
Name Wert Browser chrome
Platform WINDOWS
Browser-Version 40.0
So kann man z.B. in einem Selenium Grid mehrere Betriebssystem/Browser/Browser-Version-Kombination laufen lassen, ohne dass es zu ungewollten Konflikten kommt.
Testen bei Browserstack.com
Bei einer kleineren Testing-Suite ist es eher unwahrscheinlich, dass Browser und deren Versionen miteinander kollidieren. Aber bei einem sehr großen Grid, wie z.B. bei Browserstack, welche ein flüssige funktionierende Selenium-Umgebung bereitstellen, sollte man es sich angewöhnen seine
DesiredCapabilities
genau anzugeben, also mit Browser-Version und Betriebssystem.Bevor man Browserstack aber nutzen kann, muss man sein PHP-Script etwas anpassen:
<?php $host = 'http://hub.browserstack.com/wd/hub/'; $safari = DesiredCapabilities::safari(); [...] $safari -> setCapability ( 'browserstack.user', "username" ); $safari -> setCapability ( 'browserstack.key', "userkey" );
So weiß Browserstack nämlich, unter welchem Account die Tests durchgeführt werden.
Opera 28 und Chrome in einem Grid
Die Implementierung von Opera in das Selenium Grid ist seit Neuestem etwas tricky. Denn Opera basiert bereits seit einiger Zeit auf der Chrome-Engine Blink und verwendet somit seit der Version 26 nicht mehr den OperaPrestoDriver, sondern den OperaChromiumDriver.
Deswegen muss man auch bei der Implementierung ins Selenium Grid einiges beachten, damit man zwischen Chrome und Opera unterscheiden kann:
OperaChromiumDriver: Starten des Opera-Nodes
java -jar C:/selenium/selenium-server-standalone-2.44.0.jar \ -role webdriver \ -hub http://swuser-xubuntu:4444/grid/register \ -browser browserName=*****chrome*****,maxInstances=4,platform=WINDOWS,version=*****opera28***** \ -Dwebdriver.*****chrome*****.driver=C:/selenium/*****operachromedriver.exe***** \ -port 5558 # Man beachte die mit ***** hervorgehobenen Stellen
In der Versionsangabe steht also explizit
opera28
. Der Selenium Opera Node, der hier gestartet wird, ist also mit dieser Versionskennung eindeutig ausgewiesen.Die Parameter des Startbefehls eines Google Chrome Nodes sehen im Vergleich zum Opera Chromium Node wie folgt aus (Unterschiede sind fettgedruckt):
Parameter Chrome Opera Chromium browserName
chrome
chrome
version
40.0
opera28 Web-Driver-Name webdriver.chrome.driver
webdriver.chrome.driver
Web-Driver-Pfad C:/selenium/chromedriver.exe
C:/selenium/operachromedriver.exe Die Unterschiede bestehen also in der Versionsangabe und im Pfad zur binären Datei des WebDrivers.
OperaChromiumDriver:
chrome
als DesiredCapabilities angeben<?php $opera = DesiredCapabilities::chrome ( );
(Ja, obwohl es Opera werden soll, muss man hier
chrome
als DesiredCapabilities angeben)Um jetzt im PHP-Code zwischen einem Google Chrome Node und einem Opera Chromium Node unterscheiden zu können, spezifiziert man einfach die oben angegebene Version:
<?php # Google Chrome: $chrome = DesiredCapabilities::chrome ( ); $chrome->setVersion('40.0'); # Opera Chromium: $opera = DesiredCapabilities::chrome ( ); $opera->setVersion('opera28');
Aufrufen der Startseite
Jetzt können wir einen RemoteWebdriver wie folgt verwenden, um die betreffende Seite aufzurufen:
<?php $driver = RemoteWebDriver::create ( $host, $opera, 5000 ); $driver -> get("http://www.budenheim.com");
Ansprechen von Objekten
Um in Selenium ein Objekt anzusprechen, gibt es einige Möglichkeiten zur Auswahl:
- Über die Klasse des Elements (
class
-HTML-Attribut) - Über die ID des Elements (
id
-HTML-Attribut) - Über den XPath des Elements
Die Übersicht aller Möglichkeiten gibt die Autovervollständigung in Eclipse:
In unserem Beispiel suchen wir Elemente anhand ihres XPath aus.
Kleines Helferlein: Firepath
Mit der FirePath-Extension von FireBug für Firefox kann man den XPath zu einem bestimmten Objekt schnell und einfach herauszufinden oder einen bereits vorhanden XPath auf Richtigkeit zu prüfen:
Den XPath kann man aus dem oberen Feld übernehmen und in seinen Testplan implementieren.
In den PHP-Bindings für Selenium spricht man ein Element mit der XPath-Methode wie folgt an:
<?php $object = $driver -> findElement ( # Das ist die für uns relevante Stelle: WebDriverBy::xpath("//*[contains(text(),'Deutsch')]") );
Jetzt kann ich über die Variable
$object
auf die Funktionen und Attribte des Elements, der den TextDeutsch
enthält, zugreifen und ggf. verändern.Ladezeiten überbrücken
Das ist ja schön, dass wir unsere Seite aufgerufen haben. Aber wie überbrückt man jetzt die Ladezeit? Was ist, wenn in der Seite Elemente dynamisch nachgeladen werden (AJAX)?
PHP-sleep()-Methode
Man kann entweder die Holzhammermethode anwenden und im PHP-Script einfach ein
sleep(10)
einbauen. Der Nachteil dieser Methode ist aber, dass das Testing so sehr viel unnötige Wartezeit beinhaltet. Das ist nicht mehr optimtiert und auch einfach nicht sauber programmiert.Warten auf Existenz eines Objekts
Viel besser ist es hier, auf ein bestimmtes Objekt zu warten, bis es vorhanden ist. Dabei sprechen wir das Objekt über XPath an:
<?php $driver -> wait ( 10 ) -> until ( WebDriverExpectedCondition::presenceOfAllElementsLocatedBy ( WebDriverBy::xpath("//*[contains(text(),'Deutsch')]") ) );
Selenium wartet hier maximal
10
Sekunden, bis das Objekt existiert. Wenn nicht, wirft es eine Exception.Auf Ausführung von AJAX warten
Das gleiche Prinzip wenden wir an, wenn wir auf die Ausführung von AJAX warten: Wir triggern eine asynchrone Ausführung von einem Script, z.B. indem wir einen Link anklicken …
<?php $object->click();
… und wieder auf ein Element warten:
<?php $driver -> wait ( 10 ) -> until ( WebDriverExpectedCondition::presenceOfAllElementsLocatedBy ( WebDriverBy::xpath("***** XPath des zu erwartenden Elements hier eintragen*****") ) );
Prüfen des Inhalts eines Elements
Da wir unser Objekt bereits in der Variable
$object
referenziert haben, kann man auch ganz leicht auf dessen Eigenschaften (und logischerweise auch den Text) zugreifen:<?php $objectText = $object -> getText();
Diesen Text kann man dann je nach Testimplementierung prüfen und dementsprechen reagieren.
Screenshot erstellen
Wenn z.B. der Inhalt eines Elements nicht korrekt ist, kann man von der Seite einen Screenshot erstellen:
<?php $driver -> takeScreenshot ( '/tmp/screenshot.png' );
Die Bildschirmaufnahme kann man dann entweder weiter bearbeiten (zuschneiden, bestimmte Elemente hervorheben, etc.) oder in seine Reports integrieren.
Selenium Tutorial: Automated Website-Testing lohnt sich
Mit Selenium kann man also nach etwas Einrichtungszeit effektive und zeitsparende Website-Tests implementieren. Um mehr Funktionsumfang zu erreichen, ist es möglich Linux-Tools über PHP anzukoppeln und weitere PHP-Bibliotheken, zum Beispiel zur Reportgenerierung, einzubinden. Da die PHP-Selenium-API objektorientiert ist, hat man eine große Bandbreite an Möglichkeiten, die bei entsprechender Implementierung nicht nur sehr gut wartbare Testanweisungen ermöglichen, sondern auch der Qualität der „in die Mangel genommenen“ Website zugutekommen.
Infografiken: © schwarzer.de, Titelbild: I, Luc Viatour [GFDL, CC-BY-SA-3.0 or CC BY-SA 2.5-2.0-1.0], via Wikimedia Commons
- Über die Klasse des Elements (
Auch Interessant:
24. Juli 2020
„Welche Aufgaben sollte Künstliche Intelligenz übernehmen?“ Zwei Vorschläge und ein Gedanke.
Es vergeht kein Tag, an dem man nicht liest,…
15. Januar 2016
PowerShell: Testautomatisierung von MS Office
Testautomatisierung: Wir kennen das Problem Man…
3. Juli 2015
ElasticSearch Tutorial: Das Konzept verstehen
Der Suchserver ElasticSearch ist schwer im…