Automatische Browsertests mit Selenium: JSON Dateiformat und Test-Suite (Teil 2)

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 erste 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 wird ein erweitertes Beispiel erstellt und der Einsatz der Test-Suite erklärt.

Im dritten Teil [2] der Blogpost Reihe geht es um Tipps und Tricks in Verbindung mit GUI-Elementen (z. B. CKEditor, Farben, Tooltips, Menüs und Dialog-Boxen). In den späteren Teilen wird auf ein Client-Server-Szenario mit Selenium Grid im Zusammenspiel mit dem CI Server Jenkins eingegangen.

Das JSON Dateiformat

Wie wir im ersten Teil bereits gelernt haben, speichert Se Builder die Tests standardmäßig im Dateiformat JSON ab. Das vom Se Builder verwendete Format macht den Versuch, eine Brücke zu schlagen zwischen dem Format der strikten Aufzählung von Schritten, wie es in Selenium IDE verwendet wird und den Anforderungen der API von Se Builder [3]. Der Quellcode des abgeschlossenen Beispiels aus Teil 1 dieser Blogpost Reihe sieht wie folgt aus:

{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "get",
      "url": "http://blog.exensio.de/"
    },
    {
      "type": "clickElement",
      "locator": {
        "type": "css selector",
        "value": "body"
      }
    },
    {
      "type": "setElementText",
      "locator": {
        "type": "name",
        "value": "search"
      },
      "text": "Consulting"
    },
    {
      "type": "clickElement",
      "locator": {
        "type": "css selector",
        "value": "input.gsc-search-button"
      }
    },
    {
      "type": "waitForTextPresent",
      "text": "(Teil 3) - Fokus"
    },
    {
      "type": "clickElement",
      "locator": {
        "type": "link text",
        "value": "exensio it blog: ClaretPortal wird mobil (Teil 3) - Fokus ..."
      }
    }
  ],
  "data": {
    "configs": {},
    "source": "none"
  },
  "inputs": []
}

Das Format im Einzelnen hat eine Art Kopfzeile, einen Body und eine Art Fußzeile. In der Kopfzeile wird die Version des Selenium Tools definiert, für die dieses Skript geschrieben ist und es wird die Version des JSON Formats festgelegt.

Der Rumpf enthält alle auszuführenden Schritte, teilweise mit Zusatzinformationen, teilweise negiert. Der einfachste Fall ist:

"type": "get",
"url": "http://blog.exensio.de/"

In diesem Beispiel wird das Kommando "get" mit dem Argument "http://blog.exensio.de/" verwendet. Die Verwendung der Funktion "setElementText" sieht dagegen wie folgt aus:

"type": "setElementText",
"locator": {
  "type": "name",
  "value": "search"
  },
"text": "Consulting"

In diesem Beispiel verwendet die Funktion "setElementText" einen Locator vom Typ "name" mit dem Wert "search". In das mit diesem Locator gefundene Element wird der Text "Consulting" eingegeben. Statt des Locators vom Typ "name" wäre auch u. a. ein Locator vom Typ "css selector" möglich gewesen. In diesem Fall hätte der Wert "input[name='search']" angegeben werden müssen. Alternativ dazu wäre auch der Typ "xpath" möglich gewesen. Der Wert würde dann "//div[@id='CustomSearch1_form']/form/table[1]/tbody/tr/td[1]/input" lauten.

Die Fußzeile enthält schließlich die evtl. vorhandenen Eingangsdaten. Eine typische Fußzeile sieht wie folgt aus und muss normalerweise nicht nachträglich im Editor bearbeitet werden:

"data": {
   "configs": {},
   "source": "none"
  },
"inputs": []

Neben diesen Gestaltungselementen für Test-Skripte gibt es Lokatoren, die zur Lokalisierung bzw. Definition von Zielen dienen, die Möglichkeit der Negation, falls eine Bedingung nicht zutreffen soll und das Speichern und Verwalten von Variablen.

Später in dieser Reihe werden wir alle diese Elemente näher betrachten und in einem Beispiel verwenden. Wir werden lernen, wie man Tests schnell und effizient über mehrere Dateien hinweg in einem Texteditor bearbeitet. Mit der Zeit werden wir feststellen, dass nicht jeder neue Schritt im Se Builder aufgezeichnet werden muss.

Tipp: Locators

Se Builder selbst bietet bereits eine ganz gute Möglichkeit, die unterschiedlichen Typen von Lokatoren zu verwenden und die tatsächlich benötigten Werte ausfindig zu machen. Reicht einem der bestehende Funktionsumfang von Se Builder nicht oder möchte man tiefer in das Thema CSS Selector oder XPath einsteigen, empfehle ich die Firefox Erweiterungen FirePath [4] und FireBug [5]. Mit FirePath kann man XPath Ausdrücke bzw. CSS- und jQuery-Selektoren bearbeiten, untersuchen und generieren. FireBug enthält eine Fülle an Web Entwicklungswerkzeugen, mit denen man CSS, HTML, und JavaScript in Echtzeit an jeder beliebigen Webseite untersuchen und bearbeiten kann.

Zusammenstellen einer Test-Suite

Mit dem bisher Gelernten lassen sich schon einige Skripte erstellen und damit viele Testfälle abdecken. Im professionellen Einsatz kann es allerdings sinnvoll sein, umfangreiche Testfälle in kleine Teil-Testfälle zu schneiden. Als Beispiel sei der Vorgang Anmelden bzw. Abmelden am System genannt. Für diesen Testfall könnte man genau ein Test-Skript aufnehmen. Allerdings scheint es geschickter zu sein, den Testfall zu untergliedern in den Fall „Anmelden“ und den Fall „Abmelden“. Auf diese Weise können die Teil-Testfälle in anderen Testfällen wieder verwendet werden. Dadurch spart man sich unnötigen Aufwand bei der Verwaltung der Testfälle (z. B. bei Änderungen am Anmeldevorgang). Das Abspielen der einzelnen Testfälle kann natürlich manuell im Se Builder erfolgen, indem zuerst der Anmelde-Testfall geöffnet und abgespielt wird. Und danach wird der Abmelde-Testfall geöffnet und abgespielt. Dieses Vorgehen ist allerdings langsam und ineffizient. Selenium hat stattdessen die Test-Suite eingeführt. Dabei handelt es sich um eine Gruppierung von einzelnen Testfällen, die in der angegebenen Reihenfolge nacheinander abgespielt werden. Eine Test-Suite wird ebenfalls im JSON Dateiformat abgespeichert.

Erstellen wir dazu ein kleines Beispiel, das wir später mit dem Testfall aus Teil 1 dieses Blogposts zu einer Suite kombinieren werden. Wir wollen die korrekte Funktion der Tag Cloud auf der rechten Seite des exensio IT Blogs prüfen. Dort finden wir eine Sammlung aller Labels, die in den Blogposts verwendet wurden. Klickt man ein Label an, werden alle Blogposts angezeigt, die mit diesem Label getaggt wurden.

Öffnen wir zunächst die Webseite des Blogs unter http://blog.exensio.de im Hauptfenster von Firefox. Danach starten wir das Add-on Se Builder (Strg+Alt+B) und klicken den Knopf "Selenium 2", um die Aufnahme eines neuen Testfalls für Selenium WebDriver zu beginnen. Der erste Schritt mit dem Kommando "get" ist bereits angelegt. Nach Klicken auf den Tag Cloud Begriff "IT-Consulting" werden alle Posts mit dem Label "IT-Consulting" angezeigt. Im Se Builder wurde ein zweiter Schritt mit dem Kommando "clickElement" hinzugefügt. Jetzt können wir die Aufnahme mit dem Knopf "Stop recording" beenden und den Rest per Hand eingeben. Hierzu fügen wir unterhalb des zweiten Schritts einen weiteren Schritt hinzu ("new step below"). Das Kommando "clickElement" ersetzen wir durch "verifyText" im Abschnitt "Verify". Diese Funktion erwartet die Argumente "locator" und "text". Definieren wir zuerst den Locator in dem wir auf das Wort "locator" und danach auf "Find a different target" klicken. Wählen wir dann im Firefox Hauptfenster die Box mit dem Text "Posts mit dem Label IT-Consulting werden angezeigt. Alle Posts anzeigen" und dem Hintergrund in grauer Farbe, siehe nachfolgende Abbildung:

Der Locator Typ im Se Builder wechselt sogleich zu "css selector" und der Wert "div.status-msg-body" wird übernommen. Bestätigen wir diese Änderung zunächst mit Klick auf den Knopf "Ok". Als Wert für das Attribut "text" geben wir den Text "Posts mit dem Label IT-Consulting werden angezeigt. Alle Posts anzeigen" ein. Das fertige Skript sieht dann wie folgt aus:

In der Test-Suite, die wir später erstellen wollen, werden wir zuerst unser Test-Skript aus Teil 1 dieser Blogpost Reihe starten. Darin führen wir bereits das Kommando "get" mit dem Wert "http://blog.exensio.de/" aus. Daher benötigen wir diesen Schritt im zweiten Testfall nicht mehr. Deshalb bewegen wir den Mauszeiger im Se Builder über den ersten Schritt mit dem Kommando "get". Links erscheint daraufhin ein Kontextmenü des Se Builders. Dort wählen wir den Eintrag "delete step" um den ersten Schritt zu löschen. Im exensio IT Blog wird auf Inhalte von Twitter verwiesen. Deren Ladezeit kann unter Umständen unerwartet groß sein. Um einen Timeout des Test-Skripts zu vermeiden, fügen wir zu Beginn des Skripts noch eine Pause ein. Dazu bewegen wir den Mauszeiger über den ersten Schritt, klicken im Kontextmenü den Eintrag "new step above" und wählen dann als Kommando die Funktion "pause" im Abschnitt "Misc". Dieses Kommando erwartet als Argument einen Wert in Millisekunden. Wir geben "500" ein und speichern dann das Skript ab. Das Skript sieht nun wie folgt aus:

Jetzt können wir unser Skript schließen, indem wir im Se Builder Menü "File" den Eintrag "Discard and start over" anklicken. Danach klicken wir auf der Grundebene des Se Builers den Text "Open a script or suite" an und wählen im anschließenden "Datei öffnen"-Dialog unser JSON Skript aus Teil 1 der Blogpost Reihe aus. Nun wählen wir im Se Builder Menü "Suite" den Eintrag "Add script from file" aus und fügen unser gerade erstelltes zweites Skript hinzu. Daraufhin lädt Se Builder das zweite Skript. Das erste Skript ist allerdings nicht geschlossen, sondern befindet sich nun an erster Stelle in unserer Test-Suite. Um die vollständige Test-Suite anschauen zu können, klicken wir wieder auf das Menü "Suite". Das Submenü von "Suite" ist jetzt umfangreicher und besteht aus den Einträgen "Save", "Discard", "Record", "Add", "Remove" sowie aus den beiden Test-Skripten. Das Test-Skript, welches aktuell im Builder angezeigt wird, ist fett dargestellt. Zuerst sollten wir jetzt unsere neue Test-Suite abspeichern. Klicken wir dazu im Menü "Suite" den Eintrag "Save suite".

Test-Suite abspielen

Abschließend sind wir bereit die Test-Suite das erste Mal abzuspielen. Noch steht die Suite allerdings auf unserem zweiten Test-Skript. Natürlich wollen wir mit dem ersten Skript beginnen, deshalb wechseln wir zunächst auf das erste Test-Skript. Dazu wählen wir im Menü "Suite" den Namen unseres ersten Test-Skriptes aus. Anschließend können wir die Suite abspielen, indem wir im Menü "Run" den Eintrag "Run suite locally" anklicken. Daraufhin öffnet sich im Se Builder ein zweiter Dialog, in dem die beiden Skripte unserer Suite aufgelistet werden. Wie bereits vom Abspielen eines Test-Skriptes bekannt, ändert sich auch in diesem zweiten Dialog die Hintergrundfarbe entsprechend dem Status beim Abspielen. Am Ende werden die Schritte des letzten Test-Skriptes und alle Test-Skripte der Suite angezeigt, vgl. nachfolgende Abbildung:

Um sich die Ergebnisse der einzelnen Test-Skripte anschauen zu können, kann man im "Suite-Fenster" rechts auf die entsprechenden Namen der Testfälle klicken. Danach werden alle Schritte des Testfalls mit den zugehörigen Hintergrundfarben im Builder angezeigt. Auf diese Weise lassen sich die Tests anschließend gut untersuchen.

JSON Quellcode der Suite

Werfen wir abschließend einen kurzen Blick auf den Quellcode der Selenium Test-Suite, die wir gerade erstellt haben. Der Quellcode sieht wie folgt aus:

{
  "type": "suite",
  "seleniumVersion": "2",
  "formatVersion": 1,
  "scripts": [
    {
      "where": "local",
      "path": "test_blogpost_teil_1.json"
    },
    {
      "where": "local",
      "path": " test_blogpost_teil_2.json"
    }
  ]
}

Der prinzipielle Aufbau ist uns schon vom JSON Format der Skriptdatei bekannt. Die Suitedatei besitzt den Typ "suite" und verfügt nur über eine "Kopfzeile". Die "Fußzeile" gibt es dagegen nicht. Im Rumpfbereich gibt es nur die Funktion "where" mit dem Argument "path", dessen Wert dem Pfad zu unserem Test-Skript entspricht. Man kann hier entweder absolute oder relative Pfade angeben.

Im nächsten Teil dieser Reihe gebe ich einige nützliche Tipps zum Erstellen von sehr umfangreichen Test-Suiten. Außerdem werden Tricks verraten, wie man z. B. Eingaben in den bekannten WYSIWYG Editor CKEditor simuliert und wie Tooltips der Klasse jQuery Tooltipsy ausgelesen werden oder wie man mit Alert Boxen umgeht.

Kategorien: SeleniumTesting

Zurück