Automatische Browsertests mit Selenium: Se Builder in Verbindung mit Selenium Grid (Teil 5)

von Roland Rickborn

Diese 6-teilige Blogpost-Reihe befasst sich mit dem Thema Test-Automatisierung für grafische Benutzeroberflächen von Webanwendungen. Im Wesentlichen kommt die Selenium Test Tool Suite zum Einsatz. Im Speziellen wird der Umgang mit dem Tool Se Builder erklärt, mit dem Tests aufgenommen und abgespielt werden können.

Der ersten Teil [1] gab eine kurze Einführung zum Tool Selenium Builder, die Installation sowie einen Vergleich des Tools mit der Selenium IDE. Im zweiten Teil [2] haben wir das Selenium JSON-Format untersucht und eine Test-Suite erstellt. Im dritten [3] und vierten Teil [4] habe ich Einblicke in meine Arbeit gegeben und versucht, Fallstricke aufzuzeigen.

In diesem Teil zeige ich, wie man ein Selenium Grid einrichtet und wie man es mit dem Se Builder verwendet. Im letzten Teil wird es dann um automatisierte Tests zusammen mit dem CI Server Jenkins.

Warum Selenium Grid?

Mit Selenium Grid lassen sich Testläufe auf unterschiedlichen Maschinen mit verschiedenen Browsern parallel ausführen. Im Wesentlichen ermöglicht Selenium Grid die verteilte Ausführung von Testläufen. Es erlaubt die Ausführung der Testläufe in einer verteilten Testumgebung. Laut Dokumentation und Kommentare der Entwickler [5], sprechen die folgenden beiden Gründe für den Einsatz von Selenium Grid:

  • Bei Testfällen mit unterschiedlichen Browsern, unterschiedlichen Betriebssystemen und parallelen Testläufen
  • Um Zeit bei der Abarbeitung der Testläufe zu sparen

Obwohl Claretportal natürlich ein Multiuser-System ist und problemlos mehrere User-Interaktionen gleichzeitig bedienen kann, beschränken wir uns bei den Testläufen auf einzelne Testszenarien. Es kommen keine parallelen Testläufe zur Anwendung. Trotzdem haben wir uns für Selenium Grid entschieden, und zwar aus den folgenden Gründen: 

  • Selenium Grid im Zusammenspiel mit dem CI Server Jenkins
    Das Grid kann sehr einfach über ein PlugIn des Continous Integration Servers Jenkins in unsere bestehende Systeme eingebunden werden.
  • Unterschiedliche Browser
    Wir müssen die Kompatibilität zum Internet Explorer 8 (IE8) sicherstellen. Gleichzeitig entwickeln wir aber unter Chrome. Und natürlich wollen wir die Unterstützung moderner Browser gewährleisten. Selenium Grid bietet dafür eine große Flexibilität.

Wie funktioniert Selenium Grid?

Ich beziehe mich hier nur auf die Version 2.x von Selenium Grid, oft auch als Grid 2 oder Grid 2.0 bezeichnet. Selenium Grid verwendet ein Hub-Node-Konzept. Der Hub weiß, welche Nodes mit welchen Eigenschaften ihm zur Verfügung stehen und steuert entsprechend alle Testläufe. Als Anwender interagiert man einzig mit dem Hub.
Den Nodes wird beim Start per Parameter oder besser per JSON Konfigurationsdatei mitgeteilt, welche Eigenschaften sie anbieten können. Beispielsweise kann man einen Node starten und ihm mitteilen, er dürfe eine IE8 Instanz anbieten. Der Node meldet sich dann bei seinem Hub mit dieser Information an. Sobald der Hub eine Anfrage für einen Testlauf unter IE8 erhält, prüft er, ob er einen Node mit dieser Eigenschaft kennt und ob der Node zur Zeit zur Verfügung steht (also angemeldet und frei ist). Treffen die Kriterien zu, wird der Testlauf vom Hub angenommen und an den entsprechenden Node weiterdelegiert. Dem Node werden dann alle benötigten Informationen weitergereicht [6].

Selenium Grid Hub Installation und Konfiguration

Ich möchte hier zwei mögliche Arten der Installation zeigen. Zum einen gibt es auf der Webseite des SeleniumHQ die Standalone Variante von Selenium Grid zum Download. Damit kann man sich sein eigenes Grid, bestehend aus Nodes und Hub, einrichten und betreiben. Zum anderen gibt es das Plugin für Jenkins. Damit wird das Selenium Grid, also Nodes und Hub, in Jenkins eingebunden. Außerdem zeige ich, wie man die Nodes und den Hub mittels einer JSON Konfigurationsdatei einrichtet.

Variante 1: Standalone

  1. Voraussetzung: Java ist installiert und Classpath entsprechend gesetzt
  2. Download des selenium-server-standalone-*.jar von [7].
    Aktuell wird dort die Version 2.42.2 zur Verfügung gestellt.
  3. Hub starten durch den Kommandozeilenaufruf
java -jar selenium-server-standalone-2.*.jar -role hub

Dabei wird der Hub größtenteils mit Standardwerten gestartet (Timeouts, Ports).


Variante 2: Mittels Jenkins

  1. Ggf. Jenkins aktualisieren
  2. Über Verwaltung | Plugins das Plugin mit der ID selenium [8] installieren
  3. Ggf. das Plugin selenium aktualisieren
  4. Über den Link http://<jenkinsurl>/selenium/configurations kann der Hub des Selenium Grids konfiguriert werden.

Durch Variante 2 erhält man sehr einfach und schnell einen funktionierenden Selenium Grid Hub. Durch den sehr guten und stabilen Update-Mechanismus von Jenkins und die große Aktivität bei der Entwicklung des Plugins ist man auf diese Weise immer auf dem neuesten Stand.

Selenium Grid Node Installation und Konfiguration

Die Verwendung und die Konfiguration eines Selenium Grid Nodes ist unabhängig von der Verwendung und der evtl. vorhandenen Konfiguration eines Jenkins Slaves. Ein Node muss manuell eingerichtet werden. Es besteht nicht die Möglichkeit, eine fertige Node-Konfiguration vom Jenkins-Server zu beziehen. Die Konfiguration und der Start eines Selenium Grid Nodes ist sehr einfach und funktioniert wie folgt: 

  1. Voraussetzung: Java ist installiert und Classpath entsprechend gesetzt
  2. Download selenium-server-standalone-*.jar von http://docs.seleniumhq.org/download Aktuell wird dort die Version 2.42.2 zur Verfügung gestellt.
  3. Node starten durch den Kommandozeilenaufruf
java -jar selenium-server-standalone-2.*.jar -role node \
-hub http://<jenkinsurl><jenkins-server>:4444/grid/register</jenkins-server>

Dabei wird der Node größtenteils mit Standardwerten gestartet (Timeouts, Ports)

Wesentlich besser und komfortabler ist die Konfiguration per JSON Konfigurationsdatei, die wie folgt aussehen kann:

{
  "capabilities":
      [
        {
          "browserName": "firefox",
          "version": "29",
          "platform": "WINDOWS",
          "maxInstances": 3,
          "seleniumProtocol": "WebDriver",
          "binary": "c:\Program Files (x86)\Mozilla Firefox\firefox.exe"
        },
        {
          "browserName": "chrome",
          "version": "35",
          "platform": "WINDOWS",
          "maxInstances": 3,
          "seleniumProtocol": "WebDriver",
          "binary": "c:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
        },
        {
          "browserName": "iexplorer",
          "version": "11",
          "platform": "WINDOWS",
          "maxInstances": 1,
          "seleniumProtocol": "WebDriver"
        }
      ],
  "configuration":
  {
    "nodeTimeout":240,
    "nodePolling":2000,
    "maxSession": 3,
    "timeout":30000,
    "port": 5555,
    "host": ip,
    "register": true,
    "registerCycle": 5000,
    "cleanUpCycle":2000,
    "hubPort": 4444,
    "hubHost": <jenkins-server>
  }
}
</jenkins-server>

Hinweise: 

  • Bei der Angabe von Versionsnummern (vor allem bei Chrome) bedenken, dass sich die Version durch den Auto-Update-Mechanismus des Browsers ändern kann. Also entweder die Versionsangabe gar nicht erst angeben oder die Auto-Update-Funktion deaktivieren.
  • Beim Matching des Betriebssystems (bzw. genauer der Plattform) wird empfohlen, ausschließlich Großbuchstaben zu verwenden um Missverständnisse zu vermeiden.
  • Browsernamen mit Leerzeichen (z. B. "internet explorer") vermeiden.
  • Die maximale Anzahl an Instanzen je Node sollte auf 5 oder 6 beschränkt sein. Eine größere Anzahl an Instanzen verlangsamt den Node zu sehr.
  • Als Protokoll verwende ich ausschließlich WebDriver. Stattdessen wäre aber auch Selenium möglich. Dann würde statt des WebDrivers das RC1 Protokoll von Selenium verwendet werden.
  • Natürlich muss "" durch den Servernamen oder die IP Adresse des Jenkins Servers ersetzt werden.

Entschließt man sich für die Verwendung einer JSON Konfigurationsdatei für den Node, dann sieht der Aufruf zum Start des Nodes wie folgt aus:

java -jar selenium-server-standalone-2.*.jar -role node -nodeConfig nodeconfig.json

Bei erfolgreicher Verbindung des Nodes mit dem Hub erhält man in Jenkins unter dem Link http://<jenkinsurl>/selenium/ eine gute Übersicht über die vorhandenen Nodes und deren Konfiguration.

Tipp: Autostart Selenium Grid

Für die Nodes verwenden wir VMs von modern.UI, die jeden morgen automatisch gestartet und abends heruntergefahren werden. Damit der Selenium Node automatisch gestartet wird, empfehle ich folgende Konfiguration: 

  • Installation von TightVNC Server
  • Autologin eines beliebigen Users in dessen Kontext dann der Node gestartet wird
  • Batch-Skript im Autostart-Ordner des Users
  • Für IE und Chrome müssen die Treiber-Dateien IEDriverServer.exe und chromedriver.exe nach C:\Windows kopiert werden

Diese Konfiguration hat gegenüber z. B. der Konfiguration als Windows-Dienst den Vorteil, dass Screenshots am Node gemacht werden können. Denn ein Windows-Dienst hat kein grafisches Ausgabegerät. Screenshots resultieren in diesem Fall in einem schwarzen Bild. Mit der vorgeschlagenen Konfiguration können dagegen Testfälle erfolgreich auf dem Node abgespielt werden; inklusive der Erstellung von Screenshots. Dabei ist es nicht erforderlich, dass während des Abspielens ein User per VNC eingeloggt sein muss. Ist man dennoch eingeloggt, kann man die automatische Fernsteuerung des Browsers gut beobachten.

Testfall Remote ausführen

In den letzten Teilen dieser Blogpost Reihe haben wir bereits gelernt, wie man einen Testfall oder eine Test-Suite aufnimmt, ihn editiert und ihn später lokal abspielt. Der Vorteil im Grid besteht nun darin, dass Testfälle nicht mehr nur lokal abgespielt werden können, sondern auch remote auf einem anderen PC. Dabei kann man beim Absetzen des Jobs an den Hub angeben, mit welchen Eigenschaften der Job abgespielt werden soll.
In unserem Szenario steht neben unserem lokalen PC (der nicht Teil des Grids sein muss!) ein Node mit Firefox 29, Chrome 35 und IE8 zur Verfügung. Unser Testfall führt zu einer Webseite, die die User-Agent Angabe des Browsers auswertet. Das Skript sieht wie folgt aus:

{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "get",
      "url": "http://kluge.in-chemnitz.de/tools/browser.php"
    },
    {
      "type": "saveScreenshot",
      "file": "\\\\share\\myScreenshot.png"
    }
  ],
  "data": {
    "configs": {},
    "source": "none"
  },
  "inputs": [],
  "timeoutSeconds": 60
}

Das Skript öffnet die Webseite und macht einen Screenshot des Inhalts. Um den Testfall remote abzuspielen, öffne ich im Se Builder im Menü Run den Eintrag "Run on Selenium Server".

Daraufhin öffnet sich ein neuer Dialog mit dem Titel "Selenium Server Settings", in dem die IP-Adresse oder der Name des Selenium Grid Hub inkl. Port angegeben wird. Außerdem kann man dort spezifizieren, mit welchem Browser, welcher Version und auf welcher Plattform der Testlauf abgespielt werden soll. Diese Angaben sind optional und schränken die Auswahl verfügbarer Nodes ein.

Im ersten Schritt dieses Beispiels habe ich in dem neuen Dialog als Browser String den Wert "iexplorer" angegeben. Vergleiche dazu den Wert des Parameters browserName aus der JSON Konfigurationsdatei des Node, der ebenfalls "iexplorer" lautet. Außerdem habe ich als Browser Version "8" und als Platform "WINDOWS" angegeben. Nach Drücken des Knopfs "Run" ändert sich der Status rechts oben im Se Builder zu "connecting…". Gleich danach beginnt das Abspielen des Testfalls im Se Builder, parallel dazu ändert sich die Statusanzeige im Selenium Grid Hub (in unserem Fall in Jenkins -> Selenium Grid -> Status). Die freien und verfügbaren Browser-Instanzen werden dann wie folgt angegeben:

chrome 3/3, firefox 3/3, iexplorer 0/1

Die einzige verfügbare Internet Explorer Instanz auf diesem Node ist also derzeit belegt.
Öffnet man z. B. mittels TightVNC Viewer den Desktop des entfernten Rechners, so kann man dort das Browserfenster beobachten, wie es sich scheinbar auf magische Art und Weise von alleine öffnet und die im Testfall gespeicherten Schritte abgespielt werden. Für erfolgreiches Abspielen des Testfalls auf dem entfernten Rechner ist es nicht erforderlich, dass der Desktop mittels VNC geöffnet wird.
Ich habe den Testfall zwei Mal abgespielt und dabei den Browser String (und die Browser Version) geändert von iexplorer 8 zu firefox 29. Die Auswertung der User-Agents sieht wie folgt aus:

Bei den Selenium Tests wird also der tatsächliche User-Agent, also auch der tatsächliche Browser verwendet. Anders war es auch nicht zu erwarten, denn es wird ja mit dem Selenium WebDriver kein Browser simuliert, sondern tatsächlicher der definierte Browser verwendet.

Tipp: Unterschiedliche Browser verwenden

Bei der Verwendung von unterschiedlichen, entfernten Browsern sind folgende Dinge zu beachten: 

  • Browser sollten im selben User Context gestartet werden wie der Selenium Grid Node Task.
  • Jeder Browser sollte mindestens ein Mal manuell im entsprechenden User Context gestartet werden, um die typischen Einstellungsabfragen zu deaktivieren (Standardbrowser, Seite übersetzen, etc.).
  • Automatische Update-Funktionen der Browser sollten deaktiviert werden.
  • Identische Standard-Sprache der Browser einstellen.
  • Firefox: zu verwendendes Profil definieren [10].
  • Internet Explorer: Identische Sicherheitsstufen für alle vier Zonen.
  • Identische Startseite oder keine Startseite für alle Browser.

Im letzten Teil dieser Reihe demonstriere ich ein Szenario mit Selenium Grid und dem Continous Integration Server Jenkins, mit dessen Hilfe Testläufe automatisch gestartet werden und der das Reporting übernimmt. Außerdem zeige ich, wie sich damit Testreihen realisieren lassen.

Kategorien: SeleniumTesting

Zurück