JavaScript-Injection mit dem Robot Framework und Selenium

Keine Kommentare

Wir haben uns in meinem Team unter anderem der Akzeptanztest-getriebenen Entwicklung verschrieben. Dazu nutzen wir mit größter Begeisterung das Robot Framework und die dafür verfügbare Selenium Library. Die Tests schreiben wir in natürlichsprachlicher Form. Für komplexe Webanwendungen benötigt man von Zeit zu Zeit Überprüfungen, die als Standard-Keywords nicht verfügbar sind. Ich möchte mit diesem Beitrag vorstellen, wie man JavaScript in die getestete HTML-Oberfläche injizieren und anschließend die Erfüllung einer Bedingung verifizieren kann.


Im konkreten Fall haben wir eine Webseite entwickelt, auf der verschiedene Versicherungsprodukte nach einer Berechnung verglichen werden. Da die Seite klug ist, werden die Produkte nach der Berechnung anhand unterschiedlicher Kriterien sortiert. Außerdem gibt es für den Besucher der Website die Möglichkeit, die Produkte zu filtern. Wählt er einen Filter, so werden bestimmte Produkte ausgeblendet.

Wir müssen also für den Akzeptanztest selbstverständlich auch die Sortierung und die Filterung automatisiert testen. Ich verwende die Filterung hier als Beispiel. Der Testfall sieht abstrahiert so aus:

*** Keyword ***
Verhalten
    [Arguments]  ${Filter}  ${o1}  ${o2}
 
    Es existiert eine Produktseite für XYZ 
 
    Wenn der Filter auf ${Filter} gesetzt wird
 
    Dann ist das Produkt A optisch ${o1}
    Und außerdem ist das Produkt B optisch ${o2}
 
| *Test Case* | | *Filter*    | *o1*       | *o2*       |
| 1 | Verhalten | kein Filter | sichtbar   | sichtbar   |
| 2 | Verhalten | F1          | unsichtbar | sichtbar   |
| 3 | Verhalten | F2          | sichtbar   | unsichtbar |

Um die Sichtbarkeit eines Elements zu prüfen, gibt es keine vorgefertigten Keywords in der Selenium Library. Per Selenium IDE hat man zwar die Möglichkeit „assertVisible“ zu verwenden, wir nehmen aber lieber JavaScript dafür. Unsere Seiten nutzen Prototype, was einige sehr komfortable Methoden mitbringt. Um die Sichtbarkeit eines Elements zu prüfen, hatte ich folgende Idee:

  1. Erweitern des DOM-Trees um ein hidden input
  2. Diesem input mitteilen, ob das zu überprüfende Element sichtbar ist
  3. Anschließend per „Text Field Value Should Be“ den Wert des Felds prüfen

Gesagt getan – folgende JavaScript-Funktion sollte effizient das versteckte input-Element herbeizaubern und mit einem Wert versehen:

function prepareHiddenField() {
  if(!$('HIDDENROBOT')) {
    Element.insert(
      $('produkte'),
      new Element(
        'input',
        {type:'hidden', id:'HIDDENROBOT'}
      )
    );
  }
 
  $('HIDDENROBOT').value = $('produkt_A').visible();
}

Damit wir die Funktion injecten können, muss sie zu einer anonymen Funktion transformiert werden die sich sofort selbst aufruft. Außerdem muss der gesamte JS-Code in eine einzelne Zeile, um in der BDD-Syntax nicht mit Zeilenumbrüchen zu hantieren. Das Resultat (wer es lesen kann: Respekt), ergänzt um eine Variable „pid“ wie ProduktID:

(function(){!$('HIDDENROBOT') && Element.insert($('produkte'), new Element('input', {type:'hidden', id:'HIDDENROBOT'})); $('HIDDENROBOT').value=$('produkt_${pid}').visible();})()

Jetzt können wir entsprechende Keywords schreiben, die genau das sicherstellen was wir wollen:

Prepare hidden visibility field for ${Produkt}
	${pid} =  ProduktId für  ${Produkt}
	Call Selenium Api  runScript  derJavaScriptStringWieOben
 
Ist das Produkt ${Produkt} optisch sichtbar
	Prepare hidden visibility field for ${Produkt}
	Text Field Value Should Be  HIDDENROBOT  true
 
Ist das Produkt ${Produkt} optisch unsichtbar
	Prepare hidden visibility field for ${Produkt}
	Text Field Value Should Be  HIDDENROBOT  false

Vielleicht erscheint dies als umständlich, aber: die Möglichkeiten sind unbegrenzt. In vielen Fällen kommt man mit CSS- oder XPath-Selektoren nicht weiter – zum Beispiel wenn man bestimmte durch Ausblend-Effekte gesetzte style-Attribute überprüfen will oder ähnliches. Hierfür ist das Injizieren von JavaScript äußerst hilfreich.

Abschließend möchte ich auf das Testen der Sortierung zurückkommen, um ein etwas komplexeres Beispiel zu geben. Beim Sortieren wird innerhalb der Seite die tatsächliche Reihenfolge der Produkte im DOM-Tree verändert. Die neue Sortierung zu testen geht also darauf zurück, die korrekte Reihenfolge von Elementen des DOM-Trees zu überprüfen.

Wir benötigen für diesen Fall eine Anzahl n an hidden inputs, wenn wir n Produkte im Vergleich darstellen. Der Testfall sieht auszugweise und mit hartcodierten Werten so aus:

Dann ist das Produkt B an Stelle ${posB}
Und außerdem ist das Produkt A an Stelle ${posA}

Pro Produkt erzeugen wir ein hidden input Element:

(function(){
  Element.insert(
    $('produkte'),
    new Element(
      'input',
      {type:'hidden', id:'HIDDENROBOT${index}', value:$$('div.produkt')[${index}-1].id}
    )
  );
})()

Die Position wird hier als Variable „index“ als 1-basierter Wert übergeben, so dass auf dem per $$(‚div.produkt‘) ermittelten Array der Index um 1 verringert werden muss für den korrekten Zugriff.

Hier wieder das JavaScript in einer Zeile:

(function(){ Element.insert($('produkte'), new Element('input', {type:'hidden', id:'HIDDENROBOT${index}', value:$$('div.produkt')[${index}-1].id})); })()

Das Keyword für die gesamte Positionsprüfung sieht dann so aus:

Ist das Produkt ${einProdukt} an Stelle ${index}
	${pid} =  ProduktId für  ${einProdukt}
 
	Call Selenium API  runScript  derJavaScriptStringWieOben
	Text Field Value Should Be  HIDDENROBOT${index}  produkt_${pid}

In diesem Falle hätte es tatsächlich gar keine Möglichkeit gegeben, diese Überprüfung mit Selenium- oder Robot-Bordmitteln durchzuführen. Das Injizieren von JavaScript ist demnach ein großartiges Hilfsmittel zur Realisierung sehr komplexer Tests.

Ein Hinweis in eigener Sache: am 21. und 22. Juni 2010 bieten wir im Rahmen unseres Agilen Junis ein Training zur fachtestgetriebenen Entwicklung (ATDD) mit dem Robot Framework an. Trainerin ist Elisabeth Hendrickson. Es sind noch Plätze frei – es lohnt sich!

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.