Herzlich willkommen auf dem Blog der exensio GmbH

exensio ist ein unabhängiges Software-Unternehmen von erfahrenen IT Beratern und Architekten. Zu unseren Kunden zählen namhafte deutsche Großunternehmen.

exensio verbessert das Kommunikations- und Informationsmanagement von Unternehmen. Auf Basis sinnvoller und zweckmäßiger Technologien erarbeiten wir flexible und übergreifende Lösungen für webbasierte Informationssysteme. Abhängig von den Kundenanforderungen realisieren wir Web Applikationen sowie Lösungen auf Basis von Web Content Management- und Portalsystemen. Integrativ, wirtschaftlich und anwenderfreundlich!

Hier gelangen Sie zur exensio GmbH.

Donnerstag, 21. August 2014

Automatische Browsertests mit Selenium: Tipps und Tricks mit Se Builder (Teil 3)

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 [2] haben wir das Selenium JSON-Format untersucht und eine Test-Suite erstellt.

In diesem Teil gebe ich einige nützliche Tipps zum Erstellen von umfangreichen Test-Suiten. Es werden auch Tricks zum Umgang mit typischen Elementen eines Intranetportals verraten.
In den weiteren Teilen der Blogpost-Reihe geht es schließlich um das Client-Server-Szenario mit Selenium Grid sowie automatisierte Tests im Zusammenspiel mit dem CI Server Jenkins.

Herausforderungen mit Selenium Builder

Zum Kernprodukt von exensio gehört das Intranetportal Claretportal. Der große Funktionsumfang muss ausgiebig und zuverlässig getestet werden, um eine entsprechend hohe Softwarequalität des Produkts zu gewährleisten. Se Builder ist bei funktionalen Tests eine gute Unterstützung. Jedoch kann man bei der Erstellung von Testfällen einigen Tücken begegnen. Im vorliegenden Fall sind dies z.B.:
  • Die Verwendung des WYSIWYG Editor CKEditor, der in einem Popup geladen wird
  • Tooltips der Klasse jQuery Tooltipsy
  • JavaScript Menüs, die beim Überfahren mit dem Mauszeiger angezeigt werden
  • Testfallübergreifende Zustände
  • Dialog-Box Beispiele
  • ComboBox Beispiele
  • Sicherstellen der Verwendbarkeit bestimmter Browser und bestimmter Versionen, hier Internet Explorer 8
  • Einplanung von Wartezeiten

Der WYSIWYG Editor CKEditor

Der Editor wird im Claretportal üblicherweise per JavaScript in die Webseite eingebunden und steht als Objekt CKEDITOR zur Verfügung.
Probleme gibt es sowohl beim Test von Texteingaben, als auch beim Auslesen von Textinhalten des Editors. Bei Se Builder und WebDriver Tests kann Text nicht direkt in das Textfeld des Editors eingegeben werden. Beim Anlegen eines Textes ist das Textfeld hinter einem iFrame versteckt, so dass man nicht direkt darauf zugreifen kann. Beim Editieren eines bestehenden Textes ist das Textfeld zwar sichtbar und man kann direkt darauf zugreifen, allerdings dient dieser Text nur zur Anzeige. Änderungen an diesem Textfeld gehen beim Speichern verloren. Die Lösung besteht darin, per JavaScript auf die Instanz des Editors zuzugreifen. Im Selenium Builder geht das mit der Methode storeEval. Im Folgenden wird im 'Step 1' des JSON Skriptes von Selenium Builder die Instanz 'text' des CKEditors angelegt und der Text 'Automatisch eingefügter Text.' eingefügt.
{
  "type": "storeEval",
  "script": "CKEDITOR.instances['text'].setData( '<p>Mein Text.</p>');",
  "variable": ""
}
Die Methode "storeEval" akzeptiert als Argument "script" einen JavaScript-Ausdruck. Mit dem Aufruf "return" kann bei Bedarf ein Rückgabewert des JavaScript Programms zwischengespeichert werden. Im Argument "variable" würde dann der Name der Variablen für die spätere Verwendung festgelegt. Da wir keine Variable speichern wollen, können wir den Wert des Arguments leer lassen.
Beim Auslesen des Textinhalts des Editors hat Selenium Builder scheinbar ein Problem mit Zeilenumbrüchen ('\n' und '<p></p>') in Strings. Mittels Attribut "value" bzw. "GetData()" bekommt man den Wert des CKEditors zurück. Dieser Wert enthält allerdings Zeilenumbrüche. Will man den Wert direkt in Selenium Builder weiterverwenden, führt dies zu einem Fehler beim Ausführen des Skripts. Eine Lösung besteht im Ersetzen der Zeilenumbrüche vor dem Speichern der Variablen.
{
  "type": "storeEval",
  "script": "var retval = document.getElementById('text').value;retval = retval.replace(\"\",\"\");retval = retval.replace(\"\",\"\");retval = retval.trim();return retval;",
  "variable": "retval"
},
{
  "type": "storeEval",
  "script": "return CKEDITOR.instances['text'].setData('<p>' + String('${retval}' + '. Dieser Satz wurde nachträglich hinzugefügt.</p>') );",
  "variable": ""
}
Ich verwende in diesem Beispiel wieder die Methode"storeEval". Dieses Mal jedoch mit dem Aufruf "return" um den Rückgabewert JavaScript-Codes zwischenzuspeichern. Mit dem Wert "retval" des Arguments "variable" wird der Variablennamen für die spätere Verwendung des Rückgabewerts bezeichnet. Ich rufe die Methode "storeEval" zwei Mal nacheinander auf. Im ersten Schritt lese ich den Wert des Textinhalts des Editors aus und ersetze bestimmte Zeichen. Im zweiten Schritt erfolgt das Schreibe des Rückgabewertes aus Schritt 1 wieder zum Editor sowie das Einfügegen des eigenen Textes. Hier sieht man, wie im Argument "script" der Methode "storeEval" auf eine Variable des Se Builders zugegriffen wird. Im Beispiel verwende ich die Variable "retval" durch den Aufruf "${retval}".

jQuery Tooltipsy

Das jQuery Tooltip Plugin tooltipsy ist bei Webentwicklern beliebt, weil es eine schnelle und einfache Möglichkeit zur Darstellung von Tooltips bietet. Bei Se Builder gibt es hierfür die Methode "mouseOverElement" im Abschnitt "Input", die als Argument eine ID benötigt. Im Fall von Claretportal ist das jQuery plugin tooltipsy wie folgt eingebunden:

Bei der Aufnahme des Test-Skripts mit Se Builder wird deshalb ein CSS Selector verwendet, der u.a. auch die zufällige ID enthält. Im weiteren Verlauf der Aufnahme (mit der selben Session-ID, also ohne den Browser zu beenden) scheint vorerst alles zu funktionieren. Der verwendete CSS Selector ist allerdings nicht Session-übergreifend valide, so dass die Tests beim nächsten Öffnen des Browsers nicht mehr funktionieren. Die genauere Untersuchung des Elements, welches den Tooltip enthält, z.B. mit der Firefox Erweiterung FirePath, führt zu einem besser geeigneteren XPath. Der Test sieht dann wie folgt aus:
{
  "type": "mouseOverElement",
  "locator": 
    {
    "type": "xpath",
    "value": "//div[1]/div[3]/div/div/div/table/tbody/tr[2]/td[1]/div[1]/div/table/tbody/tr[1]/td[2]/span/img"
    }
},
{
  "type": "waitForTextPresent",
  "text": "Achtung"
}
Dabei ist es unbedingt empfehlenswert, den zu kontrollierenden Text des Tooltips mit der Methode "waitForTextPresent" zu prüfen. Denn die Methode "mouseOverElement" bewirkt nicht immer sofort das Erscheinen des Tooltips. Mitunter vergehen einige Sekunden, bis der Tooltip in der Art angezeigt wird, dass die Prüfung per "verifyTextPresent" funktioniert.

JavaScript Menüs

In Claretportal gibt es eine Hauptnavigation mit Menüeinträgen, die bei MouseOver Ereignissen angezeigt werden. Zunächst wurde versucht, mittels der Methode "mouseOverElement" ein Menü anzuzeigen. Dieser Versuch war allerdings nicht von Erfolg gekrönt. Ich habe unterschiedliche Lokatoren verwendet (CSS Selector, 2 x XPath, link text). Das Skript wurde immer erfolgreich ausgeführt. Allerdings wurde zu keinem Zeitpunkt das Untermenü der Hauptnavigation angezeigt. Danach habe ich versucht, den entsprechenden Menü-Eintrag des Untermenüs direkt mit der methode "clickElement" und dem bekannten CSS-Selector bzw. dem XPath anzusprechen. Allerdings verhielt sich WebDriver hier völlig richtig und quittierte diese Versuche mit der Meldung "Unable to locate element". Das Problem waren die nicht sichtbaren Menüs. Der zugehörige html Style ist "style.display = none". Als Lösung habe ich also eine "storeEval" Methode aufgerufen und darin folgenden JavaScript Code ausgeführt:
var drops = document.getElementsByClassName('drop').length;
In einer zweiten “storeEval” Methode habe ich dann diesen Code ausgeführt und damit das entsprechende Menü sichtbar geschaltet:
document.getElementsByClassName('drop')[${index}-1].style.display = 'block';
Die beiden Schritte sehen im JSON-Skript wie folgt aus:
{
  "type": "storeEval",
  "script": "return document.querySelectorAll('.drop').length;",
  "variable": "drops"
},
{
  "type": "storeEval",
  "script": "document.querySelectorAll('.drop')[${drops}-1].style.display = 'block';",
  "variable": ""
}
Anstatt "-1" statisch in den Quellcode des Test-Skripts zu schreiben, könnte dort auch eine Variable wie z. B. "${index}" verwendet werden. Dadurch wäre der Testfall flexibler.

Testfallübergreifende Zustände

Im zweiten Teil der Blogpost Reihe haben wir gesehen, dass es ratsam sein kann, einen umfangreichen Testfall in kleinere Testfälle aufzugliedern und diese in einer Test-Suite zu gruppieren. Im Folgenden verwende ich die einfache Test-Suite:
{
  "type": "suite",
  "seleniumVersion": "2",
  "formatVersion": 1,
  "scripts": [
    {
      "where": "local",
      "path": "test_blogpost_teil_3_schritt1.json"
    },
    {
      "where": "local",
      "path": "test_blogpost_teil_3_schritt2.json"
    }
  ],
  "shareState": true
}
Die Suite startet den Testfall "test_blogpost_teil_3_schritt1.json":
{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "get",
      "url": "http://blog.exensio.de/"
    },
    {
      "type": "storeText",
      "locator": {
        "type": "css selector",
        "value": "h2.title"
      },
      "variable": "teaser"
    }
  ],
  "data": {
    "configs": {
      "none": {}
    },
    "source": "none"
  },
  "inputs": [],
  "timeoutSeconds": 60
}
Außerdem wird der Testfall "test_blogpost_teil_3_schritt2.json" gestartet:
{
  "type": "script",
  "seleniumVersion": "2",
  "formatVersion": 2,
  "steps": [
    {
      "type": "setElementText",
      "locator": {
        "type": "name",
        "value": "search"
      },
      "text": "${teaser}"
    }
  ],
  "data": {
    "configs": {
      "none": {},
      "manual": {
        "retval": "Das ist ein Test"
      }
    },
    "source": "manual"
  },
  "inputs": [],
  "timeoutSeconds": 60
}
Mit den Standard-Einstellungen von Se Builder kann die Suite so nicht erfolgreich abgespielt werden. Beim Abspielen des zweiten Testfalls erhält man die Fehlermeldung "Variable not set: teaser". Das mag im ersten Augenblick verwundern, weil die Variable "teaser" im ersten Testfall explizit gesetzt wurde. Das Problem liegt an den Standard-Einstellungen von Se Builder, die beim Abspielen einer Suite die Zustände der einzelnen Testfälle streng voneinander unterschiedet. Das bedeutet, dass Variablen, Sessions und Cookies immer nur im aktuellen Testfall verwendet werden können. In manchen Szenarien mag diese Einstellung richtig sein. In unserem aktuellen Fall wollen wir den Zustand eines Testfalls auf einen anderen übertragen. Dazu setzt man im Se Builder Run Menü die Option "Share state across suite". Danach kann die Suite vollständig und erfolgreich abgespielt werden.

Der nächste Teil dieser Reihe ist eine Fortsetzung der Tipps und Tricks. Darin werde ich den Umgang mit einer AlertBox beleuchten, eine Auswahl in einer ComboBox treffen und viele Pausen setzen. Es werden zwei Beispiele für die Gestaltung von Testfälle mit dem Internet Explorer 8 gezeigt.

Links

[1] Automatische Browsertests mit Selenium: Zielvorstellung und Einführung Selenium Builder (Teil 1)
[2] Automatische Browsertests mit Selenium: JSON Dateiformat und Test-Suite (Teil 2)

Montag, 18. August 2014

Szenarien für den Einsatz von IoT und BigData: Visualsierung von großen Datenmengen (Teil 6)

Im Teil 5 dieser Blog-Post Serie wurde auf die Visualisierung von Sensordaten mit Hilfe der JavaScript-Bibliothek D3.js eingegangen. In diesem Teil möchte ich nun auf den Umgang mit großen Datenmengen am Beispiel der erfassten Wetterdaten eingehen.


Als Ziel sollen alle bisher aufgezeichneten Messdaten in einem Liniendiagramm dargestellt werden. Das Diagramm soll auch bei großen Datenmengen vergleichbar rasch verfügbar sein. Zum Erstellen der Grafiken kommt wiederum die auf D3.js basierende Bibliothek Rickshaw zum Einsatz. Als Beispiel eines solchen Diagramms werden die bisher aufgezeichneten Messpunkte der Außentemperatur dargestellt.

Mit der folgenden Query ist eine Ermittlung und Aufbereitung aller Messpunkte der Außentemperatur für die Grafik möglich. Es wird hierzu wie im letzten Teil dieser Serie schon gezeigt, die "Date Histogramm" Aggregation verwendet.

 client.search({
        index: 'sensorraspberry',
        size: 0,
        body: {
            // Begin query.
             "query":{
                 "bool" : {
                     "must" : [
                         {
                             "term": {
                                 "type": "outdoor"
                             }
                         },
                         {
                             "range" : {
                                 "created" : {
                                     "gte": "now-1y"
                                 }
                             }
                         }
                     ]
                 }
              },
              "aggs" : {
                  "temp_over_time" : {
                      "date_histogram" : {
                          "field" : "created",
                          "interval" : "1m"
                      },
                      "aggs" : {
                        "temp" : { "avg" : { "field" : "temperature" } }
                      }          
                  }
              }
            // End query.
        }


Das Laden dieser Grafik benötigt aufgrund der Größe der Daten relativ lange. Des Weiteren sieht die Darstellung "kantig" aus, da jeder einzelne Messwert aufgeführt wird. Bei Ansichten über längere Zeiträume sind gemittelte Werte für die Visualisierung ausreichend. Hierdurch ist ein rascheres Laden der Daten und eine ansprechendere Darstellung möglich. Es werden nun über 12h-Intervalle gemittelte Werte angezeigt. Dies ermöglicht die Änderung des Intervalls für die Aggregation.

"aggs" : {
                  "temp_over_time" : {
                      "date_histogram" : {
                          "field" : "created",
                          "interval" : "12h"
                      },
                      "aggs" : {
                        "temp" : { "avg" : { "field" : "temperature" } }
                      }          
                  }
              }


Interesse besteht natürlich nicht nur an gemittelten Werten, sondern auch an den einzelnen Messwerten. Aus diesem Grund ist beim Hineinzoomen das Anzeigen von exakteren Werten notwendig. Das Hineinzoomen in die Grafik wird über die bereits durch Rickshaw mitgelieferte Scrollbar realisiert.


Der angezeigte Zeitbereich kann über Graph.window.xMin bzw. Graph.window.xMax abgefragt werden. Ist die Zeitspanne kleiner als ein definiertes Intervall, z.B. ein Monat, wird die Query angepasst. In diesem Zeitbereich kann beispielsweise über eine Stunde gemittelt werden. Die zurück gelieferten Messwerte werden in ein Datenarray hineingeschrieben und nach Zeitstempel sortiert. Danach erfolgt die Aktualisierung der Grafik mit graph.update().

Als Ergebnis erhält man folgendes Liniendiagramm. Es lassen sich beliebig viele Auflösungsstufen einbauen und somit können auch einzelne Messwerte bei detaillierten Hineinzoomen angezeigt werden.


Wird ein Ausschnitt gewählt, der wieder größer als ein Monat ist, wird das Array auf die ursprünglichen Daten zurückgesetzt. Hierdurch erreicht man, dass das Datenarray stets eine begrenzte Anzahl an Messpunkten aufweist. Ein schnelles Laden der Grafik ist damit möglich.

Durch das schnelle Laden können Dashboards gebaut werden, die mehrere Grafiken zur Langzeitanalyse enthalten und trotzdem rasch aufgebaut werden.



Fazit

Für die Visualisierung großer Datenmenge ist es sinnvoll Werte in definierten Zeitintervallen zu mitteln, da andernfalls die Gefahr von langen Ladezeiten besteht. Um auch Daten im Detail betrachten zu können, sind Zoomfunktionen mit dynamischer Nachlade-Funktionen empfehlenswert. Exakte Messwerte können hierdurch ohne lange Ladezeiten dargestellt werden.

Donnerstag, 14. August 2014

Szenarien für den Einsatz von IoT und BigData: Visualisierung von Sensordaten mit D3.js (Teil 5)

Nachdem in den vorgehenden Teilen dieser Blog-Post Serie die Sensordaten erfasst und abgelegt wurden, möchte ich in diesem Blog-Post auf die Visualisierung der abgelegten Daten eingehen. Die Daten werden mit Hilfe der Aggregationen in Elasticsearch aufbereitet und anschließend über JavaScript entsprechend visualisiert.


Für die Visualisierung kommt die JavaScript Bibliothek D3.js zum Einsatz. Dabei handelt es sich um eine freie Javascript Bibliothek, die von Mike Bostock speziell zur Manipulation von datenbasierten Dokumenten entwickelt wurde. Des Weiteren wird die auf D3.js aufbauende Bibliothek Rickshaw verwendet, die ein flotteres Erstellen von Graphen ermöglicht.
Mit Hilfe der Visualisierung wird ein Dashboard erstellt, in dem Wetterdaten, beispielsweise die Temperatur oder Luftfeuchtigkeit der jeweiligen Sensoren, grafisch aufbereitet werden. Hierbei soll sowohl eine momentane Anzeige als auch eine Realtimegrafik die Daten anschaulich repräsentieren.
Als Beispiel für ein solches Dashboard wird hier die Visualisierung der Indoor Sensordaten gezeigt.


Für die Momentenanzeige werden Gauges, also Messgeräte verwendet. Diese zeigen den aktuellen Wert an und werden automatisch aktualisiert, wenn ein neuer Messwert eines Sensors vorhanden ist.
Die Realtimegrafik stellt die Messwerte der letzen 24 Stunden dar. Sobald ein aktuellerer Messwert verfügbar ist, wird dieser ebenfalls hinzugefügt. Die Realtime Grafik ist wie ein Sliding Window zu verstehen. Es zeigt stets nur die letzen 24h an. Daten, die älter als 24h sind, werden aus der Grafik entfernt, rutschen also aus dem Fenster heraus. Des Weiteren ist es möglich über eine Scrollbar unterhalb der Grafik in beliebige Bereiche hineinzuzoomen. Diese Funktion wird bereits durch Rickshaw selbst geliefert und benötigt keinen weiteren Programmieraufwand.

Queries

Zunächst müssen die erforderlichen Daten durch eine Query über Elasticsearch abgerufen werden. Um den prinzipiellen Aufbau einer solchen Query zu erläutern wird das Beispiel eines Gauge verwendet.
        
var client = getESClient();

 setInterval(function () {
  client.search({
   index: 'sensorraspberry',
   body: { 
     "query": {
    "bool": {
      "must": [
     {
       "term": {
      "type": "indoor"
       }
     },
     {
       "range": {
      "created": {
        "gte": "now-1d"
      }
       }
     }
      ]
    }
     },
     "aggs": {
    "devices": {
      "terms": {
     "field": "device",
     "order": {
       "_term": "asc"
     }
      },
      "aggs": {
     "time": {
       "terms": {
      "field": "created",
      "order": {
        "_term": "desc"
      },
      "size": 1
       },
       "aggs": {
      "temp": {
        "avg": {
       "field": "temperature"
        }
      }
       }
     }
      }
    }
     },
     "size": 0
   }
   }


Zunächst wird der Index festgelegt, aus dem die Daten abgefragt werden. Wird kein Index festgelegt, so wird über alle Indizes die Suche gestartet. Die Suche kann über mehrere Suchkriterien eingeschränkt werden. In diesem Beispiel müssen die Suchergebnisse vom Typ „indoor“ sein. Außerdem sollen nur Daten des letzten Tages gefunden werden. Folglich werden alle notwendigen Daten zur späteren Visualisierung gefunden.
Aufgrund der Anzahl der Messergebnisse ist es sinnvoll die Daten zu gruppieren. Hierzu bietet Elasticsearch die Aggregationen an. Diese ermöglichen es Suchergebnisse direkt in verschiedene „Töpfe“ (buckets) einzusortieren. Eine Aggregation kann beliebig verschachtelt sein und über mehrere Optionen frei konfiguriert werden. In diesem Beispiel wird für jeden Sensor (device) ein eigener Topf erstellt. In diesen Töpfen werden die Daten nach dem Erstellungsdatum sortiert und nur der neuste Wert angezeigt. Die maximale Anzahl der zurückzuliefernden Werte lassen sich über „size“ festlegen.

Erstellen des Gauge

Das Gauge für die Temperatur kann über JavaScript erstellt werden. Verschiedene Optionen, wie beispielsweise die Größe oder auch Farbbereiche können festgelegt werden.

 google.load('visualization', '1', {packages: ['gauge']});
    google.setOnLoadCallback(function () {
        var data1 = google.visualization.arrayToDataTable([
            ['Label', 'Value'],
            [String.fromCharCode(186) + 'C', 0]
        ]);
 
        // Create and draw the visualization.
        var options1 = {
            width: 200,
            max: 50,
            redFrom: 40,
            redTo: 50,
            yellowFrom: 30,
            yellowTo: 40,
            greenFrom: 20,
            greenTo: 30,
            minorTicks: 10,
            majorTicks: ['0', '10', '20', '30', '40', '50']
        };
        var gaugechart1 = new google.visualization.Gauge(document.getElementById('visual_temp_server'));
        gaugechart1.draw(data1, options1);

Dies reicht aus um einen Gauge zu erstellen. Das Ergebnis ist im folgenden Bild zu sehen.


Query für Realtimegrafiken

Um einen Verlauf von Messpunkten zu visualisieren benötigt man die Daten nach Datum bzw. Uhrzeit sortiert. Für diesen Anwendungsfall bietet Elasticsearch eine spezielle Aggregation, die sogenannte „Date Histogram Aggregation“. Sie unterteilt die Suchergebnisse in frei wählbare Zeitabschnitte (Intervalle).

"aggs": {
 "devices": {
   "terms": {
  "field": "device",
  "order": {
    "_term": "asc"
  }
   },
   "aggs": {
  "time": {
    "terms": {
   "field": "created",
   "order": {
     "_term": "desc"
   },
   "size": 1
    },
    "aggs": {
   "temp": {
     "avg": {
    "field": "temperature"
     }
   }
    }
  }
   }
 }
},
 
In unserem Beispiel wird von den Sensoren alle 2 Sekunden ein Wert geliefert. Dies führt zu einer großen Anzahl an Daten. Für die Visualisierung genügt es gemittelte Werte, z.B. über Minuten, anzuzeigen. Die Query des Gauge muss nur leicht verändert werden, um die notwendigen Daten zu erhalten. Diese werden  anschließend in einem Array ablegt.

Erstellen der Grafik mit Messpunkteverlauf

Um die nun gewonnenen Messpunkte zu visualisieren, kommt die schon erwähnte Bibliothek Rickshaw zum Einsatz. Es muss lediglich der Graph erstellt und mit den Daten befüllt werden. Optionen welche Art von Graph bzw. auch welche Farben welchen Daten entsprechen sollen, lassen sich beliebig zuweisen.

var graph = new Rickshaw.Graph( {
              element: document.getElementById("chart_temp_indoor"),
              height: 300,
              renderer: 'line',
              stroke: true,
              preserve: true,
              series: [
              {color: 'steelblue', data: dataserver, name: 'Serverroom'},
              {color: 'green', data: dataroom1, name:'Office'},
              {color: 'red', data: dataroom3, name: 'Meeting room'},
              {color: 'brown', data: outside, name: 'Outdoor'},
              ]
              } );


Verschiedene Zusätze wie Legenden oder die Scrollbar können optional hinzugefügt werden. Das Ausführen des JavaScript führt zu folgender Darstellung.

 
Um nun zu erreichen, dass aus dem statisch aufgebauten Graphen eine Realtime Anzeige der letzen 24h wird, müssen neue Daten hinzugefügt, bzw. ältere Daten aus der Grafik entfernt werden. Hierzu wird die JavaScript Funktion setInterval() verwendet. In dieser wird in definierbaren Zeitabständen eine Query abgesetzt, die lediglich die neusten Werte der Sensoren als Ergebnis zurückbekommt. Die Query ist somit identisch mit der Gauge-Query .
Liegt nun ein neuer Messwert vor wird dieser mit der Arrayfunktion push(neuerMesswert) zu dem jeweiligen Datenarray hinzugefügt. Um den ältesten Messwert zu entfernen wird die Funktion shift() verwendet.
Sind die neuen Daten im Datenarray eingepflegt, kann die Grafik mittels graph.update() aktualisiert werden. Dies reicht bereits aus damit die Grafik Realtimefähig wird.

Fazit

Über Elasticsearch kann man einfach Queries bauen, die nach mehreren Kriterien gefiltert werden können. Die Ergebnisse der Suche lassen sich durch die Aggregation für den jeweiligen Zweck in verschiedene „Töpfe“ (buckets) gruppieren.
Durch die Verwendung der Bibliotheken D3 und Rickshaw können Daten ohne großen Programmieraufwand visualisiert werden. Da D3 auf Effizienz ausgelegt ist werden die Seiten auch mit mehreren Grafiken schnell aufgebaut.  

Montag, 4. August 2014

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

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.

Links

[1] Automatische Browsertests mit Selenium: Zielvorstellung und Einführung Selenium Builder (Teil 1)
[2] Automatische Browsertests mit Selenium: Tipps und Tricks mit Se Builder (Teil 3)
[3] https://github.com/sebuilder/se-builder/wiki/JSON-Format
[4] https://code.google.com/p/firepath
[5] https://www.getfirebug.com

Montag, 21. Juli 2014

Automatische Browsertests mit Selenium: Zielvorstellung und Einführung Selenium Builder (Teil 1)

Diese 6-teilige Blogpost-Reihe befasst sich mit dem Thema Test Automatisierung für grafische Benutzeroberflächen von Webanwendungen. Im ersten Teil wird eine kurze Einführung über das Ziel, welches mit den automatischen Tests mit Hilfe des Werkzeug Selenium Builder erreicht wird, gegeben. Des Weiteren wird auf die Installation der Software eingegangen und es erfolgt ein Vergleich mit dem Vorgänger-Tool, der  Selenium IDE, welche häufiger verwendet wird, aber einige Nachteile aufweist. Abschließend wird die Funktionsweise anhand eines kleinen Beispiels dargestellt.

In den weiteren Teilen der Blogpost-Reihe geht es um ein komplizierteres Beispiel mit mehreren Schritten sowie um Tipps und Tricks in Verbindung mit GUI Elementen (z. B. CKEditor, Farben, Tooltips, Menüs und Dialoge). Ebenfalls wird auf ein Client-Server-Szenario mit Selenium Grid im Zusammenspiel mit dem CI Server Jenkins eingegangen.

Warum Selenium Builder?

Ein gängiges und weit verbreitetes Tool für automatisiertes GUI Testing einer Web Applikation und die Aufzeichnung der Testfälle ist das Firefox Add-on Selenium IDE [1]. Die Neuentwicklung Se Builder wird auf GitHub gehostet und unter der Apache 2 Lizenz veröffentlicht. Gegenüber der Selenium IDE bietet Se Builder bisher noch einen geringeren Funktionsumfang [2][3]. Die nachfolgende Tabelle zeigt den vollständigen Funktionsumfang von Se Builder:
Die Funktionsumfänge von Selenium IDE, die noch nicht in Se Builder enthalten sind, werden nachfolgend aufgeführt:
Die aktuellste Liste aller Methoden gibt es auf der Homepage des Projekts bei GitHub [4]. Die verfügbaren Methoden untergliedern sich in die Gruppen:
  • Navigation
  • Input
  • Misc
  • Assertion
  • Verify
  • Wait und
  • Store
Der große Vorteil von Se Builder liegt in der Unterstützung des Browser-Treibers Selenium WebDriver. Damit ist es möglich, fast jeden beliebigen Browser native fernzusteuern. Das bedeutet ihn genauso zu steuern, wie wenn ein menschlicher Anwender den Browser bedienen würde. Es stehen die folgenden Treiber zur Verfügung [5]:
  • AndroidDriver
  • ChromeDriver
  • EventFiringWebDriver
  • FirefoxDriver
  • HtmlUnitDriver
  • InternetExplorerDriver
  • PhantomJSDriver
  • RemoteWebDriver
  • SafariDriver
Außerdem unterstützt Se Builder den Selenium Server mit seiner eingebauten Grid-Funktion [6]. Damit ist es möglich, ein eigenes Grid an Testrechnern zu betreiben und komplette Testreihen auf verteilten Knoten zu fahren. Beispielsweise könnte eine Testreihe die Tests einer Webanwendung mit den Browsern Internet Explorer IE8 bis IE11 vorsehen.

Zielvorstellung

Zur Steigerung der Softwarequalität unserer Webanwendungen setzen wir auf kontinuierliche Integration. Dafür verwenden wir den Buildserver Jenkins [7]. Dieser Server steuert alle Softwaretests. Neben den Unit- und Integrationstests soll er insbesondere auch die funktionalen Tests steuern und kontrollieren. Außerdem sollen bestimmte Zielplattformen (insbesondere Internet Explorer 8) getestet werden können. Und zuletzt muss das Anlegen von neuen bzw. das Ändern von bestehenden Tests einfach und schnell von der Hand gehen und keine lange Einarbeitungszeit oder umfangreiches Expertenwissen erfordern.

Installation

Die Installation des Se Builders ist sehr einfach. Zuerst lädt man sich das Firefox Add-on aus dem Internet herunter. Der Anbieter Sauce Labs Inc. bietet es als XPI-Datei direkt auf seiner Homepage an unter https://saucelabs.com/builder. Alternativ kann es von GitHub unter https://github.com/sebuilder/se-builder heruntergeladen werden. Beim Download der XPI-Datei erkennt Firefox automatisch, dass es sich um ein Add-on handelt und fragt, ob es gleich installiert werden soll. Andernfalls wird das Add-on nachträglich installiert, durch Selektion der Option „Zahnrad -> Add-on aus Datei installieren“ auf der Seite about:addons.
Die grafische Benutzeroberfläche des Add-ons wird mit der Tastenkombination Strg+Alt+B im Firefox gestartet und erscheint als eigenständiger Dialog.
Ich empfehle die Spracheinstellung auf „en“ zu belassen, da die deutsche Formulierung teilweise nicht so gelungen ist. Mit der englischen Übersetzung hat man zudem gleich die richtigen Suchbegriffe parat, falls man mal Unterstützung benötigt. Nach dem Öffnen des Add-ons gibt es im Wesentlichen die beiden Alternativen:
  • Open a script or suite
  • Start recording at

Beispiel

Wir zeichnen ein kleines Beispiel auf, indem im exensio IT Blog nach dem Begriff „Consulting“ gesucht wird. Dazu wähle ich die Option „Start recording at“. Das zugehörige Textfeld ist entweder schon mit der URL http://blog.exensio.de/ gefüllt (wenn ich vor dem Start des Se Builders im Firefox die entsprechende Seite geöffnet habe). Andernfalls geben Sie im Textfeld die URL bitte an und klicken danach auf den Knopf „Selenium 2“. Wir befinden uns jetzt im Aufnahme-Modus, zu sehen an der drehenden Sanduhr im rechten oberen Eck. Se Builder hat bereits den ersten Schritt der Aufzeichnung eingetragen, nämlich get http://blog.exensio.de/. Jetzt kann man bequem den Fokus zum Firefox Hauptfenster wechseln und dort ins Suchfeld rechts klicken. Alle vorgenommenen Klicks und Eingaben, werden vom Se Builder aufgezeichnet und später in unserem Skript gespeichert. Nach Klick in das Suchfeld geben wir den Text „Consulting“ ein und klicken auf den Knopf „Suchen“. Se Builder hat dafür drei weitere Schritte aufgezeichnet:
  • clickElement css selector : body
  • setElementText locator name: search, text: Consulting
  • clickElement css selector: input.gsc-search-button
Beenden wir unsere Aufnahme vorläufig, indem wir den Fokus wieder auf das Add-on Se Builder wechseln und dort den Knopf „Stopp recording“ drücken. Jetzt sollten wir als erstes das entstandene Skript speichern. Dazu im Se Builder im Menü File den Eintrag Save anklicken und das JSON Skript an beliebiger Stelle abspeichern.

Abspielen

Jetzt ist es an der Zeit, das aufgenommene Skript zu testen. Hierzu wird am besten ein neuer Tab geöffnet. Danach öffnen wir im Se Builder das Menü Run und wählen den Eintrag „Run test locally“ aus. Der Fokus kann dabei beim Add-on Se Builder bleiben; es gibt keinen Grund, das Hauptfenster von Firefox in den Vordergrund zu holen. Schaut man sich das Firefox Hauptfenster dennoch an, sieht man wie von Geisterhand die Webseite des exensio IT Blog geöffnet wird. Danach wird im Suchfeld das Wort „Consulting“ eingegeben und sofort darauf werden die Suchergebnisse angezeigt. Schaut man sich parallel die GUI des Se Builders an, so sieht man, dass jeder unserer 4 Schritte zuerst mit gelber Hintergrundfarbe und gleich danach mit grüner Hintergrundfarbe dargestellt wird. Nachdem das Skript zu Ende durchlaufen wurde, sieht die GUI wie folgt aus.

Status und Farben

Se Builder stellt beim Abspielen die einzelnen Schritte mit unterschiedlichen Hintergrundfarben dar. Jede Farbe hat eine andere Bedeutung:

Weiß: Schritt befindet sich noch in der Warteschlange beim Abspielen

Gelb: Schritt wird gerade im Moment abgespielt

Rosa: Verify-Schritt ist fehlgeschlagen

Rot: Assert-Schritt ist fehlgeschlagen

Grün: Schritt war erfolgreich


Skript bearbeiten

Jetzt möchten wir das Skript noch um weitere Schritte ergänzen. Falls Se Builder zuvor beendet wurde, kann man jetzt nach dem Start die Option „Open a script or suite“ auswählen und das Beispielskript öffnen. Falls immer noch die vier Schritte mit grüner Hintergrundfarbe angezeigt werden, bitte den Knopf „Clear Results“ drücken. Wir wollen das Skript dahingehend bearbeiten, dass es nach dem Begriff „Consulting“ sucht und danach den Blogpost mit dem Titel „ClaretPortal wird mobil (Teil 3) - Fokus: Endless/Infinite Scrolling mit jQuery Mobile“ öffnet.

Anders als zuvor wollen wir dieses Mal die Abfolge von Klicks und Eingaben nicht aufzeichnen, sondern Schritt für Schritt eingeben. Dafür bewege ich meinen Mauszeiger über den letzten Schritt im Se Builder (clickElement css selector: input.gsc-search-button). Sogleich erscheint auf der linken Seite ein Menü welches mir diverse Möglichkeiten zur Verfügung stellt.
Ich wähle die Option „new step below“. Beim Ablegen eines neuen Schritts wird immer clickElement id: angelegt. Benötigt man eine andere Funktion, klickt man einfach auf den Funktionsnamen (hier: clickElement) und wählt dann die gewünschte Funktion aus.
Ich möchte den Fall absichern, dass sich die Darstellung der Suchergebnisse evtl. verzögert (z. B. falls der Server ausgelastet ist). Deshalb möchte ich zunächst die Funktion waitForTextPresent ausführen. Man findet sie im Abschnitt Wait. Als Argument erwartet die Funktion einen Text. Ich verwende dafür einen Teil des Titels des Blogposts, nämlich „(Teil 3) - Fokus". Anschließend füge ich noch einen Schritt unterhalb ein (erneut „new step below“ anklicken). Dieses Mal passt die vorausgewählte Funktion clickElement. Als Argument erwartet die Funktion eine ID oder eine andere Zielangabe. Klickt man auf das Wort „id“, hat man die Möglichkeit, eine ID als Freitext einzugeben.
Wesentlich bequemer ist, die Zielauswahl mit der Maus vorzunehmen. Dazu klickt man den Text „Find a different target“ an. Daraufhin springt der Fokus ins Hauptfenster von Firefox und befindet sich nun im Element-Auswahl-Modus. Jedes Element, das sich unter dem Mauszeiger befindet, wird jetzt automatisch fokussiert. Der Fokus ist an der Umrandung des Elements zu erkennen. In diesem Modus lässt sich das Wunsch-Element leicht erkennen und von anderen Elementen unterscheiden. Im Folgenden wird das Suchergebnis genau untersucht und fünf zugehörige Elemente identifiziert.




Ich entscheide mich für das zuerst ausgewählte Element (nur der Titel) und klicke dieses Element an. Der Fokus springt dann automatisch wieder zurück zum Se Builder. Außerdem wechselt der Locator-Typ von „id“ auf „link text“. Ferner wird folgender Linktext automatisch in das freie Textfeld eingetragen: „exensio it blog: ClaretPortal wird mobil (Teil 3) - Fokus ...“. Se Builder schlägt außerdem alternative Locators vor. Es liegt im Ermessen des Anwenders hier den geeigneten Locator auszuwählen. Das fertige Skript enthält danach die folgenden 6 Schritte:
Führt man das Skript nun aus, so wird die „exensio IT Blog“-Seite geöffnet, nach dem Begriff „Consulting“ gesucht, gewartet bis das Blogpost mit dem Text „(Teil 3) - Fokus" angezeigt wird und schließlich das Blogpost mit dem Titel „exensio it blog: ClaretPortal wird mobil (Teil 3) - Fokus ...“ angezeigt.

Im nächsten Teil [8] dieser Reihe erstelle ich eine Test-Suite, also eine Abfolge von Tests mit mehreren Skripten.

Links

[1] http://docs.seleniumhq.org/projects/ide
[2] https://github.com/sebuilder/se-builder/wiki/Selenium-2-Step-Support-Table
[3] http://blog.trident-qa.com/en/selenium-builder-vs-ide-list
[4] https://github.com/admc/se-builder/blob/master/seleniumbuilder/chrome/content/html/js/builder/selenium2/selenium2.js#L27
[5] http://docs.seleniumhq.org/projects/webdriver
[6] https://code.google.com/p/selenium/wiki/Grid2
[7] http://jenkins-ci.org
[8] http://blog.exensio.de/2014/08/automatische-browsertests-mit-selenium.html

Freitag, 18. Juli 2014

Warum exensio ein unabhängiges Beratungshaus ist?

Neulich erst habe ich wieder die Situation erlebt, dass eine Agentur einem Kunden angeboten hat, zu einer potentiellen Softwarelösung eine Evaluation / Auswahlberatung durchzuführen. Beim Blick auf die Homepage der Agentur konnte man leicht feststellen, dass die für die Analyse ins Auge genommenen Produkte / Hersteller als Partner der Agentur aufgelistet sind. Ist in der Konstellation eine unabhängige Beratung möglich?

exensio ist ein unabhängiges Beratungshaus. Was bedeutet das nun für uns und unsere Kunden?

  • Wir beraten unabhängig, sind unabhängig von Software-Produkt-Herstellern
  • Wir verkaufen keine Lizenzen und profitieren nicht von Lizenzverkäufen von Partnern
  • Wir führen Auswahlberatungen / Evaluationen mit einer nachvollziehbaren Methodik durch
  • Für Auswahlberatungen erstellen wir einen auf die Kunden-Bedürfnisse fokussierten Kriterienkatalog mit durch den Kunden festgelegten Gewichtungsfaktoren
  • Wir führen unabhängige Analysen des Marktes nach geeigneten Software Produkt Kandidaten durch

Mit einem strukturierten und methodischen Vorgehen schaffen wir die Basis, für eine fundierte Entscheidung. Die Entscheidung fällen natürlich die Kunden – und sie bestimmen auch den Einfluss der weichen und politischen Faktoren…

Nun werden sicher einige sofort auf die exensio Webseite schauen und feststellen, dass auch wir Partner haben - das ist richtig. Allerdings handelt es sich hierbei um Partner, mit denen exensio zusammenarbeitet, um das Dienstleistungsspektrum zu erweitern (beispielsweise für Design und Marketing oder Lean Management Beratung) oder Zugang zu tieferem Technologie Know How (beispielsweise Know How Databases von Oracle) zu erhalten.