Blog
Erstellen einer kaskadierenden Ressourcenimportstruktur für Robot Framework: Pt. 1/3 - Einführung in die gemeinsame Nutzung von Ressourcen

Dies ist der zweite Beitrag einer Serie, die sich mit einigen der Probleme und Fragen rund um die Verwendung des Robot Framework (RF) befasst, die mir in der Praxis häufig begegnen. Klicken Sie hier, um einen Blick auf den ersten dieser Beiträge zu werfen. Wie ich in der Einleitung zu diesem Beitrag erwähnt habe, werde ich diese Abhandlungen manchmal auch als Gelegenheit für kleine Exkurse nutzen, um die Interna des RF zu beleuchten.
In diesem Beitrag zeige ich Ihnen, wie Sie einen einfachen und dennoch sehr effizienten Mechanismus für die gemeinsame Nutzung von Ressourcen innerhalb des Frameworks implementieren können. Ich werde dies in
Wiederverwendbare Ressourcen
Auf höchster Ebene gibt es zwei Arten von Ressourcen, die in Ihrer RF-Testcodebasis gemeinsam genutzt werden können: Testbibliotheken von Drittanbietern und benutzerdefinierte Ressourcen. Schauen wir uns diese beiden Arten einmal genauer an.
Erste Art: Test-Bibliotheken
Wie ich bereits in einigen meiner anderen Beiträge erwähnt habe, existiert das Robot Framework innerhalb eines extrem reichhaltigen Ökosystems von gemeinsam genutzten Testbibliotheken. Dank der sehr engagierten, sehr enthusiastischen und daher sehr aktiven RF-Community wächst dieses Ökosystem schnell. Derzeit enthält es bereits Dutzende solcher Testbibliotheken. Dies sind Bibliotheken mit Schlüsselwörtern (d.h. wiederverwendbaren Testfunktionen), die Sie bei der Entwicklung Ihres eigenen Automatisierungscodes verwenden können. Die Testbibliotheken bieten somit eine sofort einsatzbereite Testautomatisierungsfunktionalität. Funktionalitäten, die Sie folglich nicht selbst entwickeln müssen! Es gibt im Wesentlichen zwei Arten von Funktionen, die von diesen Testbibliotheken bereitgestellt werden.
Arten von Testbibliotheken
Interface Treiber Bibliotheken
Eine Art von Bibliothek enthält Schlüsselwörter zum Ansteuern (d.h. Automatisieren) einer bestimmten Art von Schnittstelle, sei es eine GUI, API, ein Dienst oder ein Protokoll. Beispiele für solche Automatisierungsschnittstellen sind REST, JDBC/ODBC, HTTP, SOAP, JMS oder eine Web-GUI. Einige Beispiele für diese Art von Bibliothek sind SeleniumLibrary (früher Selenium2Library), SudsLibary, AndroidLibrary und HTTPLibrary.
Convenience-Bibliotheken
Die andere Art von Bibliothek enthält Schlüsselwörter, die alle möglichen Komfortfunktionen bereitstellen, wie z.B. das Aufteilen eines Strings, das Durchführen von Assertions in einer XML-Datei, das Lesen von oder Schreiben in eine Datei auf der Festplatte oder das Überprüfen, ob ein bestimmter Prozess läuft. Einige Beispiele für diese Art von Bibliothek sind StringLibrary, XMLLibrary, SSHLibrary und OperatingSystemLibrary.
Beispiel für eine Testbibliothek: die SudsLibrary
Mit der SudsLibrary ist es beispielsweise möglich, Domänenfunktionen für Produktfunktionen zu schreiben, die über einen SOAP-Service zur Verfügung gestellt werden, ohne dass Sie den Code schreiben müssen, um diese spezielle Art von Schnittstelle zu steuern. Die SudsLibrary abstrahiert von den Besonderheiten der SOAP-Schnittstellen und bietet Ihnen
SOAP-Client erstellen https://www.webservicex.net/globalweather.asmx?WSDL alias=WeatherService
${response}= Aufruf der SOAP-Methode GetCitiesByCountry Frankreich
Diese Schlüsselwörter abstrahieren von der Komplexität der Interaktion mit einem SOAP-Dienst und ermöglichen so prägnantere und einfachere Anweisungen in Ihren eigenen Testfunktionen. Die Schlüsselwörter der Bibliothek selbst enthalten etwa einige hundert Zeilen Code (einschließlich Anmerkungen), um diese Einfachheit zu ermöglichen. Die SudsLibrary enthält also die eigentliche Intelligenz/Logik für die Interaktion mit einem SOAP-Dienst, und durch sie hat der RF sofortigen Zugriff auf einen solchen Diensttyp.
Abschweifung: Ein kleiner Einblick in die Interna der Testbibliothek
Die SOAP-Testbibliothek von RF heißt 'SudsLibrary' (und nicht etwa SOAPLibrary), weil sie einen bestehenden (quelloffenen) Python-SOAP-Client namens'Suds' umhüllt und somit wiederverwendet. Viele (wenn nicht sogar die meisten) der RF-Testbibliotheken verpacken bestehende Python- (oder Java-) Clients von Drittanbietern. Zum Beispiel die beiden HTTP-Bibliotheken und jede der Bibliotheken für mobile Tests. Oder, ganz offensichtlich, die SeleniumLibrary. Diese Testbibliotheken verwenden alle oder einige der in diesen Clients enthaltenen Funktionen wieder, indem sie sie über die "Bibliotheks-API" von RF verfügbar machen. Dazu fügen sie lediglich eine relativ dünne Schicht von Integrations-/Klebe-/Wrapper-Code auf dem bestehenden Client hinzu. Die Wrapper-Funktionen der Testbibliothek enthalten Aufrufe zu den Client-Funktionen (in Übereinstimmung mit der API des Clients) und kombinieren manchmal (innerhalb desselben Schlüsselworts) mehrere Aufrufe zu verschiedenen Client-Funktionen, um Ihnen umfassendere, leistungsfähigere oder flexiblere Testfunktionen zur Verfügung zu stellen. Durch Letzteres wird eine zusätzliche Ebene der Bequemlichkeit hinzugefügt. Der obige Skriptcode verwendet zum Beispiel das Schlüsselwort 'SOAP-Client erstellen'. Dieses Schlüsselwort ist über die SudsLibrary verfügbar. Die SudsLibrary verfügt über ein Modul (namens 'clientmanagement.py'), das eine Python-Funktion 'create_soap_client' enthält, die das Schlüsselwort implementiert.
Dieses Schlüsselwort enthält wiederum einen Aufruf einer Klasse 'client' innerhalb eines Moduls von Suds (mit dem Namen 'client.py'), das die eigentliche Arbeit erledigt, um einen SOAP-Client wie oben beschrieben zu erstellen.
Wir können auch eine logische Ansicht erstellen:
Oder, wenn wir auf der GUI-Ebene testen wollen, könnte der Fluss durch den Stack folgendermaßen aussehen:
Etcetera! Beachten Sie, dass nicht alle RF-Bibliotheken bestehende Clients umhüllen. Die BuiltInLibrary zum Beispiel besteht lediglich aus einer Reihe kleiner Python-Funktionen (die zu Ihrem Nutzen geschrieben wurden). Auch die RF XMLLibrary umhüllt keinen Client, sondern nutzt programmatisch die Python Element Tree API (siehe die letzten beiden Bilder).
Zweite Art: Benutzerdefinierte Ressourcen
Eine Anmerkung zur Terminologie
Ich weiß: Das Folgende könnte verwirrend sein. Aber bitte, haben Sie Geduld mit mir! :-) Leider hat sich die RF-Gemeinschaft dafür entschieden, den zweiten Ressourcentyp (d.h. die benutzerdefinierte Ressource) mit dem eher allgemeinen Begriff 'Ressource' zu bezeichnen. Daher werde ich im weiteren Verlauf dieses Beitrags 'Ressource' so verwenden, wie ich es bisher getan habe, nämlich als allgemeinen Begriff, um sowohl Testbibliotheken als auch benutzerdefinierte Ressourcen als wiederverwendbare Assets zu bezeichnen. Gleichzeitig werde ich den Begriff "benutzerdefinierte Ressource" oder den Begriff "Ressource" in einfachen Anführungszeichen (also "Ressource") verwenden, um lediglich den spezifischen, benutzerdefinierten Typ einer "Ressource" im Sinne der RF-Gemeinschaft zu bezeichnen, wie weiter unten erläutert wird. Bitte beachten Sie jedoch, dass eine benutzerdefinierte Ressource innerhalb des RF-Ökosystems im Allgemeinen einfach als 'Ressource' bezeichnet wird. Also, abgesehen von der semantischen Haarspalterei, lassen Sie uns mit der Geschichte fortfahren!
'Ressource' und Ressourcendatei
Unter Verwendung der in den Testbibliotheken von Drittanbietern bereitgestellten Funktionen (wie im vorigen Abschnitt beschrieben) können Sie dann damit fortfahren, (eine oder mehrere Schichten von) eigenen, domänenspezifischen Testfunktionen zu schreiben, die als 'Benutzerschlüsselwörter' bezeichnet werden. (Eine erste, kurze Einführung in das Thema Testcode-Schichten finden Sie z.B. in diesem Blogbeitrag). Die Aufrufe dieser Bibliotheks-Schlüsselwörter werden in Ihre Kontroll-/Ablauflogik eingebettet, so dass es im Grunde genommen so ist, als würden Sie gegen eine API programmieren.
Wenn Sie z.B. einen Webshop auf der GUI-Ebene testen, können Sie die Schlüsselwörter aus der SeleniumLibrary (und anderen Bibliotheken) verwenden, um Benutzerschlüsselwörter zu schreiben, mit denen Sie z.B. automatisch die Produktfunktionalität ansteuern können, mit der Sie neue Produkte zu Ihrem Shop hinzufügen. Oder eine Reihe von Benutzer-Schlüsselwörtern, um die Produktfunktionalität zu automatisieren, mit der Sie nach vorhandenen Produkten suchen können.
Diese benutzerdefinierten Schlüsselwörter (auf höchster Ebene) bilden wiederum das Vokabular der domänenspezifischen Sprache, in der Sie Ihre Testentwürfe spezifizieren.
Der Begriff "Benutzer-Schlüsselwort" wurde daher geprägt, um die von uns, den RF-Benutzern, geschriebenen Schlüsselwörter zu bezeichnen und um diese von den Schlüsselwörtern zu unterscheiden, die von bestehenden Testbibliotheken Dritter (wie der SeleniumLibrary) bereitgestellt werden. Letztere werden passenderweise als 'Bibliotheks-Schlüsselwörter' bezeichnet.
Wichtig ist hier, dass der RF die Möglichkeit bietet, Benutzer-Schlüsselwörter, die logisch/funktional verwandt sind, in Ihren eigenen Benutzer-Schlüsselwortbibliotheken zu bündeln. Sie könnten zum Beispiel alle Benutzer-Schlüsselwörter, die mit der Suchfunktion Ihres Produkts zusammenhängen, in eine entsprechend benannte Schlüsselwort-Bibliothek extrahieren. Diese benutzerdefinierte Bibliothek kann dann in (Teilen) Ihrer Automatisierungscodebasis gemeinsam genutzt werden, um die darin enthaltenen Testfunktionen (Schlüsselwörter) wiederzuverwenden.
Wie bereits erwähnt, wird eine solche benutzerdefinierte Schlüsselwortbibliothek innerhalb von RF als 'Ressource' bezeichnet, um sie von den bestehenden 'Testbibliotheken' von Drittanbietern innerhalb des RF Ökosystems zu unterscheiden. Physisch gesehen ist eine benutzerdefinierte Ressource, wie z.B. eine benutzerdefinierte Schlüsselwortbibliothek, eine Datei. Eine einfache
Wie kann man beide Arten von Ressourcen für das Robot Framework verfügbar machen?
Um das Problem, um das es hier geht, zu verstehen, müssen wir zunächst ein paar Details zu den Organisationsprinzipien erläutern, nach denen der RF ein Testprojekt in Ordnern und Dateien im Dateisystem strukturiert.
Von Dateien und Ordnern
Auf der grundlegendsten Ebene werden Sie den RF verwenden, um Testfälle und benutzerdefinierte Ressourcen (wie z.B. Benutzerschlüsselwörter) innerhalb Ihres Testprojekts zu erstellen, auszuführen und zu pflegen. Innerhalb dieses Prozesses fungieren die vorhandenen Ressourcen als Bausteine.
Das heißt, dass Sie zunächst nur Bibliotheksschlüsselwörter zur Verfügung haben, die von Testbibliotheken wie der SeleniumLibrary bereitgestellt werden. Unter Verwendung dieser Schlüsselwörter erstellen Sie dann (verschiedene Ebenen) Ihre eigenen, domänenspezifischen Schlüsselwörter (d.h. Benutzerschlüsselwörter), indem Sie die Bibliotheksschlüsselwörter innerhalb der Ablauflogik Ihrer eigenen Funktion aufrufen. Der dritte und letzte Schritt (zumindest in diesem stark vereinfachten Überblick über den Prozess) ist die Spezifikation von Testfällen in Form von Aufrufen von Benutzer-Schlüsselwörtern.
Alles, was Sie im RF schreiben, ob es sich um Testfälle oder Benutzer-Schlüsselwörter (oder andere benutzerdefinierte Ressourcen) handelt, wird als reiner Text in einer Textdatei gespeichert. Eine Textdatei, die einen Satz von einem oder mehreren (in der Regel thematisch zusammenhängenden) Testfällen enthält, wird als 'Testsuite-Datei' bezeichnet und eine Textdatei, die eine benutzerdefinierte Ressource enthält, wie z.B. eine Sammlung von (in der Regel funktional zusammenhängenden) Schlüsselwörtern, wird als 'Ressourcendatei' bezeichnet (wie auch im vorherigen Abschnitt erwähnt).
Je nach Größe und Komplexität Ihres Testprojekts können Sie diese Dateien weiter logisch in einer strukturierten Hierarchie von Ordnern organisieren (entsprechend der gewünschten funktionalen/logischen Gliederung Ihres Projekts), um einen transparenten, verständlichen und pflegbaren Überblick über das Projekt zu erhalten. Ordner, die eine oder mehrere Testsuite-Dateien enthalten, werden auch als 'Testsuite' bezeichnet. Solche Testsuite-Ordner können neben den darin enthaltenen Testsuite-Dateien auch einen oder mehrere (Strukturen von) Testsuite-Ordner enthalten. Die Testsuite-Dateien sind immer die unterste Ebene der Testsuiten in dieser Hierarchie und in diesen Dateien sind die eigentlichen Testfälle enthalten. Schließlich können diese Testsuite-Ordner auch Ressourcendateien enthalten, z.B. eine Ressourcendatei mit den Schlüsselwörtern, die für die verschiedenen Testsuiten in diesem Ordner benötigt werden.
Dies ist natürlich nicht als Beispiel für die Strukturierung eines Testprojekts gedacht, sondern dient lediglich zur Veranschaulichung dessen, was in diesem Abschnitt gesagt wurde. Beachten Sie außerdem, dass es sich um eine Ansicht des RF-Editors 'RIDE' handelt. Was Sie auf dem Bild sehen, ist nicht der RF. Lassen Sie sich also nicht vom Aussehen und der Bedienung dieses Editors abschrecken (was eigentlich nicht ungewöhnlich ist).
Importieren von
RF-Artefakte
Wir sind nun auf die folgenden Arten von RF-Artefakten gestoßen:
- Testsuite-Ordner: enthält einen oder mehrere Testsuite-Ordner und/oder eine oder mehrere Testsuite-Dateien
- Testsuite-Datei: enthält einen oder mehrere Testfälle
- Ressourcendatei: enthält eine oder mehrere benutzerdefinierte Ressourcen, wie z.B. Schlüsselwörter und/oder Variablen
- Testbibliothek: z.B. ein Python-Modul oder eine Java-Bibliothek, die eine Reihe von Bibliotheksschlüsselwörtern enthält
Wie bereits erwähnt, kann eine Testsuite-Datei auch Ressourcen enthalten, d.h. Schlüsselwörter und/oder Variablensätze, die für einen oder mehrere der enthaltenen Testfälle spezifisch (d.h. skaliert) sind. Aber das können wir hier ignorieren, denn im Allgemeinen sollten alle Ressourcen in Ressourcendateien extrahiert werden (und werden es im Allgemeinen auch). Aus diesem Grund können und werden Testsuite-Ordner oft auch Ressourcendateien enthalten. Im weiteren Verlauf dieses Beitrags werde ich jedoch für einen Ansatz werben, bei dem Testsuiteordner niemals Ressourcendateien enthalten.
Welche davon können wiederverwendet werden?
Die Artefakte, die (potenziell) wiederverwendbar sind, sind natürlich die Testbibliotheken und die Ressourcendateien. Da es sich jedoch um separate und unabhängige Artefakte handelt, hat keines von ihnen "Kenntnis" von der (Existenz der) anderen. Um also etwas wiederverwenden zu können, müssen wir dem 'verbrauchenden' Artefakt die Existenz des 'bereitstellenden' Artefakts 'bekannt' machen. In RF, wie auch in anderen, ähnlichen Frameworks, geschieht dies durch eine Import-Anweisung, genau wie in einem Python-Modul oder einer Java-Klasse. Hier würden wir zwei externe Testbibliotheken sowie zwei benutzerdefinierte Ressourcendateien wiederverwenden:
Welche von ihnen werden andere wiederverwenden?
Die Artefakte, die solche Importanweisungen enthalten können, um andere Artefakte wiederverwenden zu können, sind:
- einen Testsuite-Ordner (innerhalb einer __init__.txt-Datei, die Python dazu veranlasst, den Ordner wie ein Paket zu behandeln):
- Warum: um Setups/Tear-Downs auf den gewünschten Parent-Suite-Ebenen definieren zu können
- was: daher wird es hauptsächlich benutzerdefinierte Ressourcen importieren (aber manchmal auch Testbibliotheken), da solche Setups/Tear-Downs normalerweise domänenspezifisch sein müssen
- eine Testsuite-Datei:
- Warum: um Testfälle in Form von domänenspezifischen Funktionen schreiben zu können
- was: Daher werden in der Regel Ressourcendateien und keine Testbibliotheken importiert, da Testfälle keinen Code und keine technischen Arbeitsschritte der untersten Ebene enthalten sollten.
- eine Ressourcendatei:
- Warum: Wie bereits erwähnt, werden benutzerdefinierte Ressourcen (wie z.B. ein Benutzerschlüsselwort) durch die Wiederverwendung bestehender Ressourcen in Testbibliotheken und/oder Ressourcendateien erstellt.
- was: daher wird es hauptsächlich Testbibliotheken importieren, aber auch andere Ressourcendateien, wie z.B. Variablendateien und/oder Bibliotheken mit Benutzerschlüsselwörtern; beachten Sie, dass letzteres im Allgemeinen nur Bibliotheken betrifft, die technische 'Helfer'-Schlüsselwörter enthalten, da es eine schlechte Praxis ist, Funktionen aus dem Funktionsbereich andere Funktionen aus dem Funktionsbereich aufrufen zu lassen (abgesehen von möglichen Wrapper-Funktionen ); letzteres ist jedoch Gegenstand von Diskussionen
Was ist denn 'importieren'?
Durch das Importieren weisen wir den RF im Grunde an, nach einer bestimmten Ressource (im allgemeinen Sinne) an einem bestimmten Ort (oder an bestimmten Orten) zu suchen und, wenn er sie findet, diese Ressourcen zu integrieren und uns zur Verfügung zu stellen, wodurch seine Fähigkeiten mit diesen Ressourcen effektiv erweitert werden. Wenn der RF also auf eine Importanweisung für eine Testbibliothek stößt, wird er versuchen, ein Modul mit dem angegebenen Namen an (einem) der Dateisystemorte zu finden, an denen solche Module normalerweise installiert sind. Dies ist einer der Gründe, warum wir bestimmte Werte für die Systemvariable PATH angeben müssen, nachdem wir Python installiert haben. In ähnlicher Weise kann der Klassenpfad bei der Ausführung von Jython für die Suche nach Java-Modulen von Bedeutung sein. Und noch eine andere Möglichkeit, RF mitzuteilen, wo es nach möglichen Ressourcen suchen soll, ist die Systemvariable PYTHONPATH, wie es z.B. bei der RemoteSwingLibrary der Fall ist. Wenn RF das Modul findet (und es in Übereinstimmung mit der RF Bibliotheks-API ordnungsgemäß implementiert wurde), werden die in diesem Modul enthaltenen Ressourcen für die Verwendung durch uns (und unseren Code) sowie für die Testausführung zur Laufzeit verfügbar gemacht. Wenn der RF das Modul nicht findet oder ein Problem damit feststellt, löst er eine Ausnahme aus und gibt eine entsprechende Fehlermeldung aus. Ähnlich sucht der RF beim Import einer benutzerdefinierten Ressource, z.B. einer benutzerdefinierten Schlüsselwortbibliothek, die Ressourcendatei an dem in der Importanweisung angegebenen Speicherort im Dateisystem und stellt sie, wenn er sie findet und sie korrekt implementiert ist, zur Verfügung.
[caption id="attachment_25595" align="aligncenter" width="900"]
Eine importierte externe Testbibliothek[/caption]
[caption id="attachment_25594" align="aligncenter" width="900"]
Eine importierte benutzerdefinierte Ressource[/caption]
Um genau zu sein, ist es also der RF, der von der Existenz einer Ressource erfährt, anstatt ein Artefakt von der Existenz anderer Artefakte in Kenntnis zu setzen. Durch eine Importanweisung wird der RF um die Fähigkeiten des importierten Artefakts erweitert und es ist dann möglich, die Funktionen dieses Artefakts in Ihre aufrufenden Strukturen aufzunehmen.
Als nächstes: Das Problem
Wir wissen jetzt, welche Arten von Ressourcen gemeinsam genutzt werden können, und kennen den Mechanismus, der diese gemeinsame Nutzung implementiert, ermöglicht und erleichtert. Ein solcher Mechanismus hat jedoch seinen Preis. Im nächsten Beitrag werden wir einen genaueren Blick auf die damit verbundenen "Kosten" werfen. Im dritten und letzten Beitrag werden wir eine Möglichkeit vorstellen, diese Kosten zu minimieren.
Verfasst von
Michael Hallik
Unsere Ideen
Weitere Blogs
Contact



