Mit dem javabasierenden Open Source Tool Selenium lassen sich automatisierte Browsertests auf Windows, Apple und Linux Plattformen realisieren. Das Tool bietet eine sehr große Anzahl von Schnittstellen zu unterschiedlichen Systemen und Integrationsmöglichkeiten zu fast allen bekannten Programmiersprachen. Durch die hohe Flexibilität kann man Browsertests für alle handelüblichen Browser (Firefox, Internet Explorer, Chrom, Safarie, etc,) realisieren. Es gibt sogar einige Firefox Plugins mit denen man Tests durch einfaches Screenrecording definieren und direkt ausführen kann.
Wenn man Automatisierte Browsertests in einem Continous Integration Cycle integrieren möchte, muss man sich eingehend mit den vorhanden Schnittstellen beschäftigen. In diesem Artikel möchte ich die Nutzung eines PHP Webdrivers (von Adam Goucher) im Zusammenhang mit dem CI-Server Jenkins erläutern.
Im Artikel Continous Integration, ein Bericht aus der Realität habe ich den Gesamtaufbau eines Contious Integration Prozess ausführlich dargestellt. Im weiteren Verlauf gehe ich ausschliesslich auf die Technische Umgebung und Umsetzung von automatisierten Browsertests ein. Falls nicht alles zum Thema Continous Integration bekannt seien sollte, empfehle ich den vorgenannten Artikel zuerst zu lesen.
Verschaffen wir uns zunächst einen Überlick über die verwendeten Komponenten:
In diesem Schaubild werden drei einzelne Systeme dargestellt: Jenkins- , Selenium- und ein Testserver. Ich betreibe den Jenkins Server auf einem Linux Bestriebssystem und zusätzlich ist noch PHP (in einem Apache Environment) installiert. Der Deployment Job des Jenkins Server installiert das zu testende Softwareprodukt auf dem Test Server auf der rechten Seiten. Im weiteren Verlauf des Deployment Jobs werden PHP Skripte gestartet, die die definierten Testschritte über den PHP Webdriver ausführen. Der PHP Webdriver wiederum kommuniziert mit dem Selenium Server auf dem Dritten System und dieser steuert den lokalen Browser. Innerhalb des Browsers werden dann die Testschritte aus dem PHP Testscript ausgeführt und die Ergebnisse zurückgeliefert.
Betrachten wir nun die erste Interaktion zwischen dem Jenkins Deployment Job und dem PHP Testscript. Innerhalb des Deployment Jobs kann man SSH Befehle ausführen und den Returncode auswerten. In diesem Beispiel startet im Jenkins Deployment Job die Lokale PHP Installation das PHP Testscript browsertest,php
Innerhalb des Testskriptes werden die einzelnen Selenium Testschritte ausgeführt und das Ergebnis muss als Returncode an den Jenkins Deployment Job zurückgegeben werden. Hierfür muss man innerhalb des PHP Testscriptes den Returncode festlegen und mit der PHP Funktion exit() an den aufrufenden Prozess zurückgeben.
Hierbei gilt der Returncode 1 (besser gesagt nicht 0) als Fehler:
/* an error occured returning 1 */ exit(1); |
Und der Returncode 0 als erfolgreiches Ergebnis der Testprozedur:
/* everything went fine, return 0 */ exit(0); |
Der Jenkins Server interpretiert den Returncode und verknüpft das Ergebnis mit dem Deployment Job. D.h. nur wenn der Returncode 0 zurückgegben wird, erkennt der Jenkins den Buildschritt als erfolgreich. Bei jeder anderen Ausgabe, interpretiert der Jenkins Server das als Fehler und erklärt den Deployment Job als gescheitert. Achtet daher darauf, keine anderen Zeichen zurückzugeben oder gar im Verlauf des PHP Testscriptes ein echo in die Console zu machen. Das führt ebenfalls dazu, dass der Jenkins den Buildschritt als fehlerhat interpretiert.
Soweit so gut, betrachten wir nun die Interaktion zwischen dem PHP Testscript und dem PHP Webdriver. Man kann den PHP Webdriver über das __init__,php einfach Skript einbinden und danach werden (fast) alles Aktivitäten über die Klasse PHPWebDriver_WebDriver durchgeführt:
<!--?php /* including the Webdriver framework */ require "PHPWebDriver/__init__.php"; /* setting invinite timelimit for the script, test can run a long time */ set_time_limit(0); /* setting the browsertype to test in */ $browser = "internet explorer"; /* setting the selenium server */ $host = 'selenium.local:4444/wd/hub'; /* creating the session to the selenium server */ $driver = new PHPWebDriver_WebDriver($host); /* defining the session for the webdriver */ $session = $driver--->session($browser); /* always maximizing the remotebrowser*/ $session->window()->maximize(); /* open the page */ $session->open('http://testhost.local/contactform'); //checking the page titel, if not Kontaktformular, then stop the entire test if (! (strpos($session->element("tag name", "html")->text(), "Kontaktformular") !== false)) { throw new Exception('headline Kontaktformular wasn found'); exit(1); }; /* fill the contact form with some datas */ $result = $session->element('id', 'firstname'); $result->sendKeys('Peter'); $result = $session->;element('id', 'surename'); $result->sendKeys('Lustig'); $result = $session->element('id', 'message'); $result->sendKeys('Dies ist ein Test des Kontaktformular.'); // submit the form $result = $session->element('id', 'submit')->submit(''); //need a break to wait for reload of the page sleep(10); // check if the respondse message is correct if ($session->element("class name", 'wpcf7-response-output')->displayed('') == 0) { throw new Exception('succsess respond message "wpcf7-response-output" wasn´t shown'); exit(1); } /* closing the session to the selenium server */ $session->close(); exit(0); ?> |
Der Testfall innerhalb des PHP-Testscripts füllt ein einfaches Kontaktformular aus und schickt die Eingabe zum Test Server ab. Wenn das Kontaktformular erfolgreich abgesendet wurde, gibt der Test Server eine Meldung aus, dass der Versand des Kontaktformulars erfolgreich war. Die Erfolgsmeldung wird in einem DIV der Klasse wpcf7-responds-output ausgegeben und das Testscript fragt mit ->displayed(“) ab, ob der Anwender das DIV mit der Meldung sehen kann.
Gehen wir mal weiter zur nächsten Schnittstelle und betrachten die Kommunikation zwischen dem PHP Webdriver und dem Selenium Server. Den Selenium Server einzurichten ist etwas komplexer und ich habe die notwendigen Schritte im Artikel Webdriver Testsystem für Selenium installieren und einrichten beschrieben. Der PHP Webdriver und der Selenium Server kommunizieren über den Port 44444 und im Grunde sendet der PHP Webdriver JSON Pakete mit den einzelnen Testschritten an den Selenium Server. Der Selenium Server wiederum setzt die Befehle aus den JSON Paketen um und steuert den Lokalen Browser. Die Steuerung des Browsers funktioniert entweder mit eingebauten Varianten oder Externen Webdriver Konstrukten. Im obengenannten Artikel ist ebenfalls beschrieben welche Browser in Verbindung mit welcher Webdriver Komponente genutzt werden kann.
Die Steuerung des Lokalen Browsers führt der Selenium Server durch in dem Tastatureingaben oder Mausbewegungen ausgeführt werden. Klarer Vorteil an dieser Variante ist, dass der Browser keine Unterscheidung zwischen automatisierten oder manuell durchgeführten Tests. Beispiel hierfür ist ein Mouseover Event, dass mittels Javascript in der Testseite integriert ist. Man kann mit dem folgenden Befehl den Mousepointer an die Stelle des Elements auf der Website führen und damit das Integrierte Mouseover Event auslösen:
$result = $session->element('id', 'submit')->moveto(''); |
Leider ist die API Dokumentation des PHP Webdriver nicht vollständig veröffentlicht. Man kann sich aber etwas behelfen und direkt in die PHP Skripte hineinsehen. Man findet fast alle Methoden und Eigenschaften in den beiden PHP Skripten WebDriverSession.php und WebDriverElement.php