Testautomatisierung: Struktur ist alles

04.12.2019
Günther Matthias Bär

Die Vorteile einer effektiven Struktur für die Testautomatisierung

 
Sowohl bei der Entwicklung von Software als auch in der Testautomatisierung ist es unerlässlich, eine logische Struktur aufzubauen. Das Ziel dabei ist es, zu jedem Zeitpunkt den Überblick zu behalten, die Arbeit im Team zu erleichtern und unabhängig von der Größe des Projekts wartungsfreundlich zu bleiben.
Die Strukturierung von Programmen ist ein Verfahren, dass sich zum größten Teil in der Entwicklung von Software bereits etabliert hat. Die Erfahrungen haben gezeigt, dass dies in der Gänze aber noch nicht in die Testautomatisierung durchgedrungen ist. Dabei sollten hier die gleichen Anforderungen wie in der Entwicklung gestellt werden, denn oft kann die Testautomatisierung die gleiche Komplexität erlangen wie die zu testende Software. Es gibt bereits ausreichend Beispiele, die zeigen, wie eine logische Struktur aufgebaut werden kann.

Änderungen und Anpassungen

Anwendungssoftware unterliegt in der Entwicklung einem ständigem Änderungsprozess. Mit jedem Release müssen neue Funktionalitäten überprüft werden. Dies zum Teil in unterschiedlichen Konfigurationen und/oder mit geänderten Randbedingungen (anderes Betriebssystem, unterschiedliche Browser, etc.).
Eine Testautomatisierung muss deshalb so aufgebaut sein, dass zeitnah auf jede Änderung im System Under Test (SUT) reagiert werden kann. D.h. Änderungen am Testautomatisierungs-Framework dürfen nicht mehr Aufwand bedeuten, als die durchgeführten Anpassungen im SUT.
Anforderungen hinsichtlich kürzerer Releasezyklen (Time to Market) sowie einer deutlichen Verbesserung gegenüber der manuellen Testdurchführung, wie z.B. Reduktion der Kosten, Erhöhung der Testintensität/Komplexität, kürzerer Laufzeiten und einer geringeren Fehleranfälligkeit, machen es zudem erforderlich, dass die Gesamtheit aller Testfälle in einem definiertem Zeitrahmen ablaufen müssen. Eine gut strukturierte Architektur der Testautomatisierung ermöglicht z.B. eine effektivere Lastverteilung der durchzuführenden Testfälle und kann somit den Anforderungen besser gerecht werden.
Ein weiterer wichtiger Aspekt ist die Wartbarkeit einer Testautomatisierung. Eine zentrale Verwaltung von Variablen bzw. Testdaten minimiert den zu erbringenden Änderungsaufwand. Eine vernünftige Aufteilung von themenspezifischen Funktionalitäten in eine modulare Struktur erhöht die Übersicht und erleichtert das Arbeiten im Team. Des Weiteren ist auf eine Synchronität zwischen der zu testenden Software und der Testautomatisierung zu achten, d.h. jede durchgeführte Änderung im SUT sollte einer Änderung in der Testautomatisierung einfach zuzuordnen sein.
Eine Testautomatisierungsstruktur muss es ermöglichen, dass unabhängig von der Testtiefe die Testfälle zu jedem Zeitpunkt wiederholt werden können. Dies wiederum setzt voraus, dass vor bzw. nach jedem Testlauf (Setup bzw. Teardown) die zu testende Applikation auf den Urzustand zurückgesetzt werden kann. Dies bedeutet, dass das Testdatenmanagement eigenständig behandelt und aus jeder Phase des Testlaufs ansprechbar sein muss.
Da so gut wie jedes Testframework über Monitoring- bzw. Log- und Reporting-Mechanismen verfügt, wird durch den Aufbau einer effektiven Struktur das Auffinden und Beheben von Fehlern erleichtert.
Bevor der erste Testfall erstellt werden kann, sollte man sich also zunächst über den Aufbau der Architektur der Testautomatisierung Gedanken machen. Dies mag vordergründig mehr Aufwand bedeuten, aber dieser Mehraufwand zahlt sich bezogen auf das Gesamtprojekt aus.

Ein Gleichnis aus dem Leben

Stellen Sie sich vor, Sie sollen mit einer Gruppe von Leuten aus Legosteinen ein bestimmtes Modell (Haus, Flugzeug, Schiff, etc.) in einem bestimmten Zeitrahmen erstellen. Ihnen steht hierzu eine riesige Kiste aus unterschiedlichen unsortierten Steinen zur Verfügung. Sie wären also gezwungen, jedes einzelne benötigte Teil in der Kiste zu suchen (einhergehend mit Kopfschmerzen, da sie permanent mit den Köpfen der Kollegen zusammenstoßen). Sie wüssten auch nicht, ob ein bestimmtes Teil überhaupt vorhanden bzw. verwendbar ist (da gebrochen oder ähnliches). Sie müssten also entscheiden, ob es Sinn macht weiter zu suchen oder das Teil neu zu besorgen, um im zeitlichen Rahmen zu bleiben. Sie sehen, es können vielfältige technische, administrative und logistische Probleme auftreten.
Wäre es da nicht sinnvoller, im Vorfeld etwas Mühe hineinzustecken und die einzelnen Steine zu sortieren und auf kleinere Behälter zu verteilen? Die Zeit für die Suche im Team verkürzt sich immens. Wenn ein bestimmtes Teil benötigt wird, muss nur auf das entsprechende Behältnis zugegriffen werden und man kommt sich nicht mehr zwangsläufig gegenseitig in die Quere. Fehlerhafte Teile werden zudem schneller entdeckt. Fehlende Teile können zeitnah besorgt werden.

Programmierung erleben

Ähnlich verhält es sich auch in der Software-Entwicklung. Auf Grund eines vermeintlich höheren Aufwands scheuen viele Entwickler davor zurück, sich darüber Gedanken zu machen, wie sich bestimmte Teile einer Funktionalität thematisch, funktional und logisch in einzelne Module bzw. Untermodule aufteilen lassen. Das Ergebnis sind dann meist monolithische Softwarekonstrukte (also „Kruschkisten“), die oft nur noch schwer zu verwalten sind.
Müssen in einem solchen Konstrukt nun entsprechende Änderungen vorgenommen werden, ist zu gewährleisten, dass nur eine Person diese Datei ändert, um zwangsläufig auftretende Probleme (wie z.B. gegenseitiges Überschreiben von Änderungen) zu vermeiden. Wird diese Software in einem zentralen Versionierungstool verwaltet, ist die entsprechende Datei für eine weitere Bearbeitung sowieso gesperrt, d.h. es leidet unter anderem die Wartbarkeit der Software darunter.
Allein durch den Aufbau einer logischen Verzeichnisstruktur (die die Struktur der zu testenden Software wiederspiegelt) und einer sinnvollen Vergabe von Dateinamen der einzelnen Module wird sozusagen eine Verbindung zum zu testenden System hergestellt und es lassen sich zu bearbeitende Dateien leichter auffinden. Dies erspart unnötige Sucharbeit. Durch die Verwendung kleinteiliger Module werden bei einem Testlauf auch nur noch die Teile geladen, die auch wirklich benötigt werden.

Wie kann nun so eine Struktur in der Praxis aussehen?

Als Beispiel wollen wir hier ein End-to-End-Testszenario einer Web-GUI heranziehen, das mittels einer schlüsselwortgetriebenen Testware realisiert wird.
Zunächst wollen wir die Struktur einer Web-Applikation näher betrachten: Grob gesagt besteht eine Web-Applikation aus einer Hauptseite und den entsprechenden Menü-Elementen, um auf die jeweiligen Unterseiten zu gelangen. Jede Seite enthält unterschiedliche Elemente (Lokatoren) und Funktionalitäten, die über die Testautomatisierung angesprochen werden müssen. Aus diesem Grund macht es also Sinn, die Funktionalität einer jeden aufgerufenen Seite in einem Pendant auf Seiten der Testautomatisierung abzulegen. Dadurch begrenzt sich der Umfang der Datei auf das Wesentliche, da nur die Eigenschaften der jeweiligen Seite angesprochen werden. Die Übersichtlichkeit wird erhöht und die Fehlersuche erleichtert.
Ein sehr gutes Verfahren, das hier zur Anwendung kommen kann, ist das so genannte Page/Page Object – Verfahren. Dabei wird die Testautomatisierung in drei primäre Teilbereiche unterteilt, die wie folgt beschrieben werden können:

  • Testfallbeschreibung: Je nach zu testendem Abschnitt der Applikation werden parametrisierbare Testfälle in eigenständigen Testbeschreibungsdateien definiert.
  • Abschnittsbeschreibung: In so genannten Page Files werden die entsprechenden Workflows der Abschnitte abgebildet.
  • Zustandsbeschreibung: Über so genannte Page Object Files wird die Funktionalität der jeweiligen Seite abgebildet und die anzusprechenden Lokatoren hinterlegt

Ein Vorteil dieser Strukturierung besteht unter anderem darin, dass für jede Funktionalität nur die wirklich erforderlichen Zusatzmodule integriert werden und somit ein Overhead vermieden werden kann.

Testbeschreibungsdateien

Jeder Menüpunkt einer Webapplikation stellt einen eigenständig zu behandelnden Abschnitt dar. In den einzelnen Schritten eines jeden Testfalls wird der vollständige Prozess bis hin zu dem jeweiligen Abschnitt durchlaufen, dessen Funktionalität überprüft und der Prozess wieder abgeschlossen.
Ziel der Übung ist es nun, zu entscheiden wie die Testbeschreibungsdateien so aufgeteilt werden können, dass immer nur ein Abschnitt bzw. Teilabschnitt behandelt wird. Dabei soll einerseits die Modularität und somit die Wartbarkeit erhöht, der Inhalt begrenzt und andererseits die Anzahl der zu verwendenden Dateien nicht unnötig in die Höhe getrieben werden.
Vor der Erstellung von automatisierten Testfällen in Testbeschreibungsdateien sollten also unter anderem folgende Fragen gestellt werden:

  • Wie lassen sich die dokumentierten Testfälle sinnvoll unterteilen?
  • Sollen gewisse Kategorien autark testbar sein?
  • Ist ein bestimmter Workflow bei der Ausführung einzuhalten?
  • Gibt es evtl. Überschneidungen mit anderen Testfällen?
  • Wie soll der Zugriff auf entsprechende Testdaten erfolgen?
  • Wie sollen testfallübergreifende Konfigurationen verwaltet werden?
  • Wie sollen testfallspezifische Konfigurationen verwaltet werden?


Suche vollständigen Kunden anhand Firmennamen
MainApp.Aufruf der Hauptseite
LoginApp.Anmelden auf Hauptseite ${BENUTZERDATEN.USER1}
MainApp.Waehle Option Benutzerdaten
CustomerApp.Gebe Suchkriterien ein ${TESTDATEN.SUCHE1}
Einfaches Beispiel für den Aufbau einer Testfallbeschreibung mit wiederverwendbaren Schlüsselwörtern

Einfaches Beispiel für den Aufbau einer Testfallbeschreibung mit wiederverwendbaren Schlüsselwörter

Page Files

Wie der Name schon vermuten lässt, bilden die Page Files die Funktionalität der einzelnen Abschnitte ab. Dies heißt nichts anderes, als dass die Menüführung der jeweiligen (Unter-)Seiten abgebildet und zu eigenen Schlüsselwörtern zusammengeführt werden, um die Erstellung der Testfälle zu vereinheitlichen.
Als einfaches Beispiel kann hier z.B. die Verwaltung von Personen einer fiktiven Web-Applikation genannt werden. Für das Anlegen, Bearbeiten oder Suchen von Personen sind eigenständige Seiten in der Web-Applikation vorgesehen. Jede dieser Seiten werden in der Testautomatisierung über eine eigene Datei abgebildet. Durch Aufruf von Schlüsselwörtern aus den Page Object Files können wiederum ganze Workflows zu einem Schlüsselwort in den Page Files zusammengefasst werden. Über die Möglichkeit unterschiedliche Testdaten über ein und dasselbe Schlüsselwort durchzureichen, können somit unterschiedliche Testszenarien abgebildet werden.


Gebe Suchkriterien ein
Search.Gebe Nutzerdaten ein ${TESTDATEN.SUCHE1}
Search.Betaetige Suche-Button
Einfaches Beispiel für den Aufbau eines Schlüsselwortes im Page File CustomerApp

Einfaches Beispiel für den Aufbau eines Schlüsselwortes im Page File CustomerApp

Page Object Files

Page Object Files sind die Dateien, in denen die eigentlichen Aktionen (Befüllen von Formularfeldern, Betätigen von Buttons, etc.) durchgeführt werden und stellen somit den Inhalt und die Funktionalität der angesprochenen Seite dar. In ihnen werden also auch die seitenspezifischen Lokatoren (Textfelder, Buttons, etc.) hinterlegt, die für die Ausführung/Überprüfung der entsprechenden Funktionalität erforderlich sind. Dabei ist anzuraten, die Namen der Dateien bzw. der Lokatoren so zu wählen, dass sie einen Hinweis auf die Verwendung geben und um Konflikte mit gleichlautenden Bezeichnern zu vermeiden.


Gebe Nutzerdaten ein
Input Text ${Lokator für Texteingabe} ${Wert aus Testdaten}

Einfaches Beispiel für den Aufbau eines Schlüsselwortes im Page Object File Suche

Einfaches Beispiel für den Aufbau eines Schlüsselwortes im Page Object File Suche

Aufbau einer effektiven Verzeichnisstruktur

Mit dem nun vorhandenen Wissen kann nun die primäre (Verzeichnis-) Struktur für die Testfälle und die Page- bzw. Page Object Files geplant und aufgebaut werden. Dabei ist zu beachten, dass die einzelnen Teilbereiche voneinander thematisch getrennt werden sollten. Ein Beispiel, wie eine solche Struktur aussehen kann wird in Abbildung 1 dargestellt.

Abb. 1: Verzeichnisstruktur am Beispiel einer Robot Framework Testumgebung

Der Aufbau einer solchen Struktur ist immer abhängig vom Ansatz der Testautomatisierung. Dennoch kann das grundlegende Prinzip dieser Strukturierung in den meisten Fällen angewendet werden können. Im weiteren Verlauf soll hier nur die Strukturierung der oben bereits beschriebenen primären Teilbereiche beschrieben werden.

Struktur der Testfälle

Wie bereits im Vorfeld angeklungen, macht es Sinn die einzelnen Abschnitte einer Webapplikation auf Seiten der Testautomatisierung in einer Verzeichnis- bzw. Dateistruktur abzubilden. Des Weiteren müssen auch die Belange der Testszenarien berücksichtigt werden, da bestimmte Teilbereiche mit unterschiedlichen Werten überprüft werden sollen. Dabei macht es natürlich Sinn diese Teilbereiche wiederum zu untergliedern.
Wie so etwas aussehen kann soll anhand eines Beispiels in Abbildung 2 dargestellt werden.

Abb. 2: Beispiel für eine effektive Ablagestruktur von Testfällen

Durch die Vergabe von Dateinamen (z.B. in Punktnotation) kann ersichtlich gemacht, was und welches Szenario in welcher Datei getestet werden soll, d.h. dass zum Beispiel in der Datei Customer.Search.Name alle möglichen Kriterien bei der Suche nach Namen abgedeckt werden (Name, Teilnahmen oder Sonderzeichen, etc.). Durch die Modularität dieser Struktur muss bei Änderungen in der Anwendungssoftware nur ein kleiner Teilbereich angepasst werden. Die Wartbarkeit der Testautomatisierungsumgebung wird somit erhöht, da ein zeitgleiches Bearbeiten von Dateien minimiert bzw. vermieden werden kann.
An dieser Stelle soll darauf hingewiesen werden, dass eine Aufteilung der fachlichen Abschnitte schon bereits bei der Erstellung der Testfälle mit in Betracht gezogen werden sollte, um unnötige Diskrepanzen zu vermeiden. Je sauberer eine Untergliederung vorgenommen wird, umso besser lässt sich eine Testautomatisierungsumgebung administrieren.

Struktur der Page- bzw. Page Object Files

Schon durch den strukturellen Aufbau der Testbeschreibungsdateien lässt sich gut erkennen, wie eine entsprechende Struktur bei den Page- bzw. Page Object Files aufzubauen ist. Wobei auch auf allgemeine Belange eingegangen werden muss, also Funktionalitäten die seiten- bzw. testfallübergreifend zum Einsatz kommen sollen. Abbildung 3 soll dabei verdeutlichen, wie hierbei eine saubere Trennung vorgenommen werden kann. Müssen also bestimmte Funktionalitäten angepasst werden, da Änderungen in der Applikation vorgenommen wurden, lässt sich anhand der Struktur die zu bearbeitende Datei leichter auffinden. Das Gleiche gilt natürlich auch, wenn bestimmte Bereiche entfernt werden sollen.
Des Weiteren macht es natürlich Sinn sich zu überlegen welche Funktionalitäten auf Seiten der Page Object Files (Bottom up) bereitgestellt werden sollen. Somit lässt sich erkennen welche mehrfach zum Einsatz kommen können. Dadurch lassen sich etwaige Redundanzen vermeiden.

Abb. 3: Beispiel für die Strukturierung von Page- bzw. Page Object Files

Der Aufbau einer solchen modularen Struktur hat auch den entscheidenden Vorteil, dass Aufgaben im Team besser verteilt werden können. Durch den kleinteiligen Aufbau können über ein entsprechendes Versionierungstool auch ältere Versionen eines entsprechenden Moduls eingespielt werden. Dadurch lässt sich unter anderem verhindern, dass ungewollte Änderungen ein erfolgreiches Testergebnis verhindern.
Diese Herangehensweise kann, soweit möglich, auch für alle weiteren Bereiche (wie z.B. Log- bzw. Testdatendateien) angewandt werden.

Dynamische Konfiguration

Wie in der Programmierung allgemein, so sollte eine Testautomatisierungsstruktur immer so aufgebaut sein, dass viele Programmteile wiederverwendet werden können und Redundanzen vermieden werden. Dies kann dadurch realisiert werden, indem mehrfach verwendbare Schlüsselwörter erstellt und mit unterschiedlichen Werten aus zentralen Konfigurationen bzw. Konfigurationsdateien befüllt werden. Es gilt also zu entscheiden, was eine allgemeine, übergreifende Verwendung erforderlich macht bzw. was nur in einem speziellen Fall Verwendung findet. Prinzipiell sollte eine Testautomatisierungsstruktur immer eine zentrale Konfigurationsdatei und die Möglichkeit Einfluss auf Testfall- bzw. Seiten-Ebene zu nehmen beinhalten. Dabei sollten folgende Regeln beachtet werden:

  • Pfade zu Dateien immer in einer zentralen Konfigurationsdatei anlegen
  • Variablen bzw. Zusatzmodule nur dort verwenden wo sie benötigt werden

Es gilt daher zu entscheiden, wie die einzelnen Konfigurationen so aufgeteilt werden können, dass der Änderungsaufwand minimiert werden kann.
 

Fazit

Etliche Testautomatisierungsprojekte leiden unter der Tatsache, dass nicht genügend Vorarbeit hinsichtlich der aufzubauenden Struktur geleistet wird. Damit einhergehende Probleme lassen sich aber vermeiden. Der vorgeschlagene Ansatz ist dabei nur einer von vielen Möglichkeiten wie man sich die Arbeit in der Testautomatisierung und insbesondere in einem Team erleichtern kann.
Dabei verhält es sich wie beim Bau eines Hauses:
Erst wird geplant und dann gebaut!
 
[toggle type=”” title=”Über den Autor”]
Günther Matthias Bär ist seit 2016 als Senior Consultant in der Beratung und Realisierung von Testautomatisierungslösungen bei der Sogeti Deutschland GmbH tätig.[/toggle]

0 Kommentare

Einen Kommentar abschicken

Bitte melden Sie sich an, um einen Kommentar zu hinterlassen.