Dateidownloads mit Selenium – einfach unmöglich?

Keine Kommentare

Wenn man anfängt Fachtests zu automatisieren kommt man recht schnell an den Punkt, an dem geprüft werden muss, ob über eine Weboberfläche angebotene Dokumente bestimmten Kriterien genügen. Wer das schon einmal probiert hat weiß: Dateidownloads automatisch zu durchzuführen und zu testen, ist aber einfach unmöglich … oder?

Häufige Waffe der Wahl für Tests von Web-UIs ist Selenium. In der Konstellation „Selenium vs. Download“ ergeben sich gleich mehrere Probleme, die gelöst werden müssen:

  1. Dateidownload: Der Download-Dialog, der sich nach einem Klick auf ein Dokument öffnet ist in allen Browsern nativ und kann nicht über JavaScript gesteuert werden. Eine schlechte Ausgangslage für Selenium: Ohne eine Möglichkeit auf den Dialog Einfluß zu nehmen, bleibt dieser geöffnet und der Testcase hängt.
  2. Dateitransfer: Unter der Annahme, dass das erste Problem gelöst werde kann, ergibt sich ein Folgeproblem: Falls der Selenium-Server nicht auf dem gleichen Rechner läuft, wie der Server zur Testautomatisierung, muss die gerade heruntergeladene Datei auch noch irgendwie auf den Testautomatisierungs-Server transferiert werden.

Ansätze zur Lösung des Downloadproblems

Das Problem des Dateidownloads kann auf unterschiedliche Weisen gelöst werden.

1. Fensterautomatisierung
Der erste Ansatz hat was von „Brute Force“: Sucht man im Internet nach einer Lösung findet man recht schnell Vorschläge, den Download-Dialog über eine native Fensterautomatisierung wie AutoIt fernzusteuern. D.h. man würde AutoIt so vorbereiten, dass es auf einen Download-Dialog unterschiedlicher Browser wartet, und an der Stelle an der Selenium hängen bleiben würde das Ruder übernimmt, die Datei speichert und den Dialog wieder schließt. Danach kann Selenium wie gewohnt weitermachen.

Das mag funktionieren, aber ich fand die Lösung technischen overkill, und wie sich gezeigt hat, geht es auch wesentlich einfacher.

2. Standardverhalten des Browsers anpassen
Die zweite Möglichkeit besteht darin, das Profil des Browsers dahingehend anzupassen, dass sich z.B. beim Klick auf ein PDF erst gar kein Dialog öffnet, der fragt, was der Benutzer mit der Datei anstellen möchte, sondern diese kommentarlos und ohne jede Nachfrage in ein vorbestimmtes Verzeichnis schreibt. Dazu muss mit dem entsprechenden Browser und Profil einmal ein Download durchgeführt werden, um dann dort das Standardverhalten festzulegen („Für Dateien dieses Typs immer diese Aktion ausführen“).

Na gut, das könnte funktionieren. Man muss „nur“ sicherstellen dass alle EntwicklerInnen, Hudson-Instanzen, etc das gleiche Browserprofil verwenden. Und je nach dem wieviele unterschiedliche Dateitypen heruntergeladen werden sollen, ist das auch ein kleines Stück arbeit.

3. Direkter Download
Warum eigentlich den Umweg über Selenium? Wäre es nicht viel cooler, wenn man die Datei einfach ohne Selenium runterlädt? Dann hätte man das zweite Problem auch gleich mit erschlagen. Warum eigentlich nicht, wget gibt es schließlich nicht nur für Linux, sondern auch für Windows. Problem gelöst? Nicht ganz: was ist mit Dateien, die nicht frei zugänglich sind? Was ist wenn ich erst mit Selenium einen bestimmten Zustand herstellen möchte, um dann auf eine möglicherweise generierte Datei zuzugreifen? Für öffentliche Dateien scheint die Lösung gut zu funktionieren, aber für manche Situationen ist die Lösung wohl noch nicht ausreichend.

Fazit: Downloadproblem
Ok, es ist möglich Dateien herunterzuladen, es ist aber mit etwas Arbeit und eventuell weiteren Werkzeugen verbunden. Aber der erste Schritt ist ja, dass man überhaupt eine funktionierende Lösung hat.

Was war nochmal das andere Problem?

Ansätze zur Lösung des Dateitransfer-Problems

Na gut, zugegeben, das ist kein wirkliches Problem. FTP kann heutzutage doch jeder. Fast jeder. Für unser favorisiertes Werkzeug zur Fachtestautmatisierung, das Robot Framework, gibt es leider noch keine Library, die per FTP auf entfernte Dateien zugreifen kann. Hier hieße es also mal wieder flugs eine eigene kleine Library geschrieben, was aber auch nicht so schwierig sein dürfte.

Problem gelöst

In Verbindung mit den Ansätzen 1 und 2 von oben wäre es also möglich das Problem vollständig zu lösen:

  • Datei mit Selenium herunterladen und in ein Verzeichnis schreiben, das über FTP erreichbar ist
  • Dann per FTP die Datei zum Server zu Fachtestautomatisierung transferrieren.
  • Danach können dann nach belieben Checks auf der Datei ausgeführt werden.

Puh … das sieht nach einer Menge Arbeit für ein eigentlich recht einfaches Problem aus.

Irgendwie nagt immer noch das wget an mir, was ja eigentlich nach einer sehr einfachen, aber unvollständigen Lösung aussieht … Wäre es nicht cool, wenn man wget irgendwie sagen könnte, es soll da weitermachen, wo Selenium aufgehört hat? Man kann!

Gesamtlösung

Letztendlich ist die Lösung sehr einfach und elegant, und ich frage mich, warum ich nicht direkt darauf gekommen bin — vermutlich ein Anzeichen dafür, dass die Lösung wirklich sehr einfach ist.

Wie kann man wget also sagen, es soll an dem Punkt weitermachen, an dem Selenium gerade aufgehört hat? Woher weiß ein Webserver, wer da überhaupt den Request stellt: über die aktuelle Session! Man kann wget über Cookies und Header-Parametern die Session-ID mitgeben, um dann auf die Datei zugreifen zu können. Das ganze ist als Keyword implementiert ein Zweizeiler!

Keyword "Download File"

Download File  [Arguments]  ${COOKIE}  ${URL}  ${FILENAME}
  ${COOKIE_VALUE} =  Call Selenium API  get_cookie_by_name  ${COOKIE}
  Run and Return RC  wget --cookies=on --header "Cookie: ${COOKIE}=${COOKIE_VALUE}" -O ${OUTPUT_DIR}${/}${FILENAME} ${URL}

Zuerst wird also über einen direkten Aufruf einer Methode der Selenium API ein bestimmtes Cookie ausgelesen und dessen Wert zwischengespeichert. Im zweiten Schritt wird ein neuer Prozess gestartet und so lange gewartet, bis dieser Prozess terminiert. Das ist der Fall, wenn die Datei erfolgreich mit wget heruntergeladen werden konnte. Dazu muss wget natürlich irgendwo im Pfad liegen, ansonsten wird der Test nicht funktionieren. Über den Headerparameter „Cookie:“ arbeitet wget in der gleichen Session weiter wie Selenium, und hat somit Zugriff auf die Datei. Voilà 🙂

Das neue Keyword nimmt drei Parameter entgegen

  1. COOKIE Das Cookie wird vorher über Selenium ausgelesen und dann an wget weitergegeben. Das ist üblicherweise ein Indikator für die laufende Session
  2. URL Der Link zu der Datei die heruntergeladen werden soll
  3. FILENAME Der Name unter dem die Datei in Robots Outputverzeichnis abgelegt werden soll

Gebrauch des neuen Keywords

Der Gebrauch des neuen Keywords ist jetzt schon fast trivial, trotzdem hier der Vollständigkeit halber der Download eines PDFs, das als „file.pdf“ in das Ausgabeverzeichnis gelegt wird (d.h. dort, wo auch die Reports landen). Das Cookie mit der Session-ID ist JSESSION.

Download File  JSESSIONID    http://<...>/web/pdf?id=4711  file.pdf


Dateidownloads mit Selenium – einfach möglich!

Andreas Ebbert-Karroum

Andreas Ebbert-Karroum ist Agile Principal Consultant bei codecentric und Product Owner von CenterDevice.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

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