Testautomatisierung: Arten des Testdesigns 

 25. März 2021

Testautomatisierung hat das Ziel, die Effizienz beliebiger Testaktivitäten zu steigern. Schon beim Testentwurf gibt es verschiedene Arten der Testautomatisierung, die unterschiedliche Ansätze verfolgen:

  1. Capture & Replay
  2. Skriptbasiert
  3. Datengetrieben
  4. Schlüsselwortgetrieben
  5. Modellbasiert

Mit jeder Stufe steigt auch der Anspruch an den Testentwurf. Techniken wie Capture & Replay liefern schnellere Ergebnisse, schlüsselwort- oder modellbasierte Techniken liefern jedoch dauerhafte und skalierbare Lösungen.

Die besondere Betrachtung des Testentwurfs im Rahmen der automatisierten Testdurchführung hat seine Ursache in den mehr oder weniger häufigen Änderungen, denen die Software-Entwicklung unterworfen ist. Diese können durch geänderte Anforderungen oder entdeckte Fehler bedingt sein und führen dazu, dass die manuellen Wartungsaufwände für automatisch durchführbare Testskripte bei häufigen Änderungen leicht den Vorteil der automatischen Testdurchführung zunichtemachen.

Capture & Replay

Mit „Capture & Replay“ bezeichnet man den Ansatz, die manuelle Ausführung eines Testfalls aufzuzeichnen (capture) und diese Aufzeichnung dann beliebig oft wiederholen zu können (replay). Dazu sind Testwerkzeuge notwendig, die sowohl die Handlungen des Testers aufzeichnen als auch diese danach an der Schnittstelle des Testobjekts wieder reproduzieren können. Dieser Anspruch an das Testwerkzeug steigt mit der Komplexität des Testobjekts und kann im Extremfall bis zum Einsatz von Testrobotern führen, die z.B. Hardware-Komponenten hinzufügen, ändern oder entfernen. Im einfachsten und gängigsten Fall wird diese Technik für den Test über Bedienung und Beobachtungen in einem Webbrowser genutzt. Das Testwerkzeug muss für die Aufzeichnung nur die Aktionen von Maus und Tastatur auf der Oberfläche, sowie Position und Inhalt der erwarteten Reaktionen speichern.

Zwei Möglichkeiten hierzu sind, die absoluten Koordinaten aller Mausklicks oder die Objekt-IDs (sofern vorhanden) der angeklickten Elemente zu speichern. Letzteres hat den Vorteil, dass die Neuanordnung der Oberflächenelemente nicht direkt das erneute Aufzeichnen der Testfälle bedingt. Einer der bekanntesten Vertreter für „Capture & Replay“-Tests von Web-Anwendungen ist Selenium, das die Aufzeichnung z.B. mit dem entsprechenden Plugin für den Browser Firefox ermöglicht und die Wiedergabe dieser Aufzeichnungen auf vielen der am weitesten verbreiteten Browser erlaubt.

Selenium IDE als Firefox Add-on

Selenium IDE als Firefox Add-on

Im rechten mittleren Teil ist die Abfolge von Testschritten zu sehen: im ersten Schritt wird die Base URL geöffnet. Im oberen Abschnitt ist hinterlegt, welche Webseite als Startpunkt für die Suche nach der Testmeisterei gewählt werden soll. Im zweiten Schritt wird das Suchfeld aktiviert und der Wert „testmeisterei“ eingetragen. Im nächsten Schritt wird die Suche gestartet und gewartet bis der Browser die folgende Internetseite geladen hat („clickAndWait“). Im folgenden Schritt wird der erste Eintrag aufgerufen. Im letzten Schritt wird der Inhalt der Webseite überprüft, indem die Überschrift mit dem String „Qualität ist eine Haltung“ verglichen wird. Wie die Oberfläche anzeigt, verlief der Test ohne einen Fehler aufzudecken. Die richtige Seite wurde gefunden.

Selenium ist ein sehr mächtiges Automatisierungswerkzeug. Es lassen sich damit auch die höheren Entwurfsstufen umsetzen. Das ist sogar die Regel.

Der große Vorteil von „Capture & Replay“ ist, dass Fachexperten ohne Unterstützung von Test- oder Software-Experten direkt Testfälle erstellen und ausführen können. Das geht ohne große Vorbereitungs- oder Einarbeitungszeit. Der wesentliche Nachteil besteht in dem vergleichsweise hohen Anpassungsaufwand: Bei jeder Änderung des zu testenden Systems muss der Testfall erneut aufgezeichnet werden: bei inhaltlichen Änderungen, bei Änderungen in der Reihenfolge der Bedienung oder bei minimalen Änderungen des Seitenlayouts (nur für die Variante basierend auf absoluten Koordinaten). Schon bei vergleichsweise kleinen Änderungen muss also der Großteil der Testfälle erneut erstellt werden.

Da die Testfallerstellung in der Aufzeichnung manuell ausgeführter Testfälle besteht, muss jeder Testfall also erneut manuell ausgeführt werden. Eine einzelne Änderung ist zwar (in Abhängigkeit von der Komplexität des Systems) mit geringem bis mittlerem Aufwand verbunden. Durch die hohe Frequenz von Anpassungen gemessen an Änderungen des Testobjekts sind die Testentwurfskosten jedoch sehr hoch. Daher eignet sich dieses Verfahren hauptsächlich für den Einsatz, wenn man schnell Ergebnisse demonstrieren möchte, wenn Änderungen am System eher die Ausnahme als die Regel darstellen oder lediglich ergänzend zu den später aufgeführten Ansätzen.

Skriptbasierte Testautomatisierung

In der skriptbasierten Testautomatisierung werden Testfälle in Form von ausführbaren Skripten (ausführbarer Testcode) entworfen. Der Testdesigner muss also über Programmierfähigkeiten verfügen und eine Entwicklungsumgebung verfügbar haben. Solche Testskripte können in jeder Programmiersprache entworfen werden. Auf der Ebene des Komponententests ist häufig der Einsatz von xUnit-Tests zu beobachten, d.h. Unit-Tests, die direkt in der Sprache x geschrieben werden, in der auch das zu testende Programm geschrieben wird: Für Java-basierte Programme also jUnit, für Programm in C++ cppUnit, usw. Auf der Systemtestebene hängt die Wahl der Programmiersprache am ehesten an der Testschnittstelle des zu testenden Systems.

JUnit in der Eclise-Entwicklungsumgebung.

JUnit in der Eclise-Entwicklungsumgebung.

Beispiel der Entwicklungsumgebung Eclipse mit JUnit für einen Testfall. In diesem Testfall wird das Verhalten der Klasse Tester geprüft. Diese hat eine Methode getStatus(), die eine Zeichenkette in Abhängigkeit vom internen Zustand zurückliefert. Die Klasse beschreibt einen Tester, der nach Initialisierung den Zustand „Lehrling“ und nach intensivem Lernen durch den Aufruf der Methode do_learn() den Zustand „Meister“ hat. Im linken Bereich der Abbildung zeigt die Oberfläche an, dass der Test durchgeführt wurde ohne einen Fehler zu entdecken.

Der Vorteil des skriptbasierten Testentwurfs gegenüber des Capture & Replay besteht vor allem in der Unabhängigkeit der Testfalldefinition von der Testdurchführung. Änderungen am Testentwurf sind also auch ohne die erneute Ausführung des Tests möglich. Dieses ist insbesondere bei umfangreicheren Tests von Vorteil. Die wesentlichen Nachteile des skriptbasierten Testentwurfs sind jedoch ähnlich zu denen des Capture & Replay: in vergleichsweise vielen Fällen von Änderungen müssen Testfälle manuell angepasst werden. Jedoch ist die Frequenz nicht ganz so hoch, da z.B. Änderungen wie das Verschieben von Oberflächenelementen durch die Nutzung programmiertechnischer Hilfsmittel vergleichsweise einfach in den Testentwurf übernommen werden können. Dies wäre über die Abstraktion der konkret angefragten Positionen von Oberflächenelementen in separate Klassen möglich.

Der wesentliche Vorteil ist, dass der Änderungsbedarf nicht zwangsläufig die erneute Ausführung des gesamten Testfalls nach sich zieht. Nun kann man abwägen, ob die manuelle Anpassung des Testcodes ohne Testausführung aufwändiger ist als die manuelle Ausführung eines Testfalls und das automatische Protokollieren wie im Capture & Replay-Ansatz. Das hängt im Einzelnen von der konkreten Herausforderung ab. Unsere Erfahrung zeigt aber, dass mit steigender Testdauer oder für zeitkritische Tests die Aufwände für das manuelle Ausführen deutlich höher sind als die Aufwände für die Anpassung des Testskriptes. Weiterhin kann es zusätzliche Aspekte geben wie die Erstellung und Verwendung von Screenshots in Testfällen oder während der Testdurchführung aufwendig zu erstellender Daten, die die Anpassung des Testskripts deutlich einfacher machen als die Ausführung des Tests.

Nicht zu vernachlässigen ist auch die Fehleranfälligkeit bei der manuellen Testdurchführung. Da jeder Fehler automatisch mitgeloggt wird und eine Fehlbedienung auch zu einer ungewollten Zustandsänderung führt, müsste der Test erneut von vorn aufgenommen werden, was den Aufwand für Capture & Replay weiter erhöht. Insgesamt überwiegen aus unserer Sicht die Vorteile des skriptbasierten Ansatzes gegenüber dem Capture & Replay.

Datengetriebene Testautomatisierung

Beim datengetriebenen Test (datadriven) stehen entgegen der beiden vorhergehenden Ansätze die Daten im Mittelpunkt der Betrachtung. Die Basis ist ein Testentwurf, der von konkreten Daten abstrahiert z.B. indem nur die erwarteten Parameter vorgegeben werden, aber nicht deren Werte. Der Tester hat nun die Aufgabe, passende Daten zu definieren. Diese Daten können in einem beliebigen (zum verwendeten Framework passenden) Format definiert werden. In der Praxis sind Excel-Tabellen oder SQL-Datenbanken oft gang und gäbe. Eine Art des Testentwurfs wäre es, eine Tabelle zur Verfügung zu stellen, die pro benötigten Eingabeparameter und pro erwarteten Ausgabeparameter eine Spalte zur Verfügung stellt. Der Tester muss nun in die Zeilen der Tabelle konkrete Werte eintragen. Ein Adapter stellt die Verknüpfung mit dem Testobjekt her, übergibt die Eingabeparameter und vergleicht Ist-Ergebnisse mit den vorausgesagten Ergebnissen.

Test der Division mit FitNesse

Test der Division mit FitNesse

Ein typischer Vertreter ist das Testwerkzeug FitNesse. FitNesse ist ein Wiki Webserver, der lokal auf dem PC installiert werden kann. Das heißt, dass die Daten direkt als Tabelle auf einer eigenen Test-Wiki-Seite erstellt werden können. Alternativ können die Werte im Editiermodus auch aus einer Excel-Tabelle über den Knopf „Spreadsheet to FitNesse“ importiert werden. Die obere Zeile gibt den Namen der Klasse an, die getestet werden soll, in unserem Fall Division. Die definierte Tabelle wird von FitNesse an ein Testausführungsframework übergeben (z.B. Slim), das entsprechend der Namen in der zweiten Zeile die darunter aufgeführten Werte an gleichnamige Setter-Methoden der Klasse Division übergibt bzw. das Ergebnis zu Namen mit einem abschließendem Fragezeichen von der Klasse Division abholt. Für erwartete Werte können konkrete Werte oder Wertebereiche angegeben werden. Die Testausführung kann über das Betätigen des Knopfes „Test“ gestartet werden. Je nachdem, ob das Ist-Ergebnis dem erwarteten Ergebnis entspricht oder nicht, wird die entsprechende Zeile durch FitNesse grün oder rot eingefärbt.

Schlüsselwortgetriebene Testautomatisierung

Die beiden zuvor beschriebenen Ansätze basieren auf Programmiersprachen und waren entweder auf Verhalten oder Daten fokussiert. Im Folgenden liegt der Fokus auf der Erhöhung der Wartbarkeit durch die Nutzung von zusätzlichen Abstraktionsebenen.

Beim schlüsselwortgetriebenen Testentwurf (keyword-driven) werden anstelle konkreter Befehle abstrakte Schlüsselwörter verwendet, die zur Laufzeit je nach Konfiguration in einer Adaptionsschicht durch konkrete Befehle ersetzt werden. Änderungen des Systemverhaltens, die keine Änderung des Sprachumfangs bedingen, können so durch ein Vertauschen der Schlüsselwörter vergleichsweise aufwandsarm in die entsprechenden Testfälle überführt werden. Insbesondere die verbesserte Lesbarkeit wird oft als wesentlicher Vorteil wahrgenommen. Falls sich neue Szenarien ergeben, so müssen dafür neue Testfälle geschrieben werden. Neue mögliche Systemaktionen oder –reaktionen ziehen die Erweiterung der Menge an Schlüsselworten nach sich. Es gibt zahlreiche Werkzeuge, die das schlüsselwortgetriebene Testen unterstützen. Jeder Programmierer kann ein entsprechendes Framework in Eigenregie erstellen. Etwas mächtigere Werkzeuge mit Editor-Unterstützung z.B. für Auto Completion sind xText oder Cucumber. Hiermit wird die Definition der gesamten erlaubten Sprache ermöglicht.

xText

xText

Hier Ein Beispiel in xText, mit der man Tester und Testfälle definieren und sie in Beziehung setzen kann, indem man einem Tester eine Aufgabe bezüglich eines Testfalls zuweist: er soll ihn entwerfen oder ausführen.

Instanz der xText-Sprache über Tester

Instanz der xText-Sprache über Tester

Hier eine Instanz dieser Sprache. Hier wird der Tester Klaus als Testmeister definiert mit den Aufgaben, den Testfall T1 zu entwerfen und auszuführen. Diese Sprache ist natürlich nur exemplarisch. Genauso könnten hiermit Bedienungen und erwartete Ergebnisse eines Testobjekts zueinander in Relation gesetzt werden und daraus ausführbare Testfälle abgeleitet werden.

Der wesentliche Vorteil dieses Vorgehens ist die höhere Abstraktionsebene, die das vergleichsweise leichte Erstellen und die vereinfachte Wartbarkeit der Testfälle ermöglicht. Weiterhin ist in vielen Fällen gar keine umfangreiche Anpassung notwendig, da die Testfälle sowieso in der Adaptionsschicht in konkrete Befehle umgewandelt werden: Etliche Änderungen, die z.B. das konkrete Schnittstellenformat betreffen und in den Testfällen der Adaptionsschicht hinzugefügt werden, können somit vergleichsweise aufwandsarm und einmalig für alle Testfälle in der Adaptionsschicht vorgenommen werden. Zu den Nachteilen gehört eine mittlere Komplexität in der Vorbereitung, da sowohl die Sprache, in der die Schlüsselworte zu definieren sind als auch die Aufgaben der Adaptionsschicht mit allen Stakeholdern abgestimmt werden müssen.

Rein von den technischen Möglichkeiten lassen sich diese Ergebnisse auch mit dem skriptbasierten Ansatz erreichen. Allerdings ist hierzu eine umfangreiche Vorbereitung in Form von zu schaffenden Abstraktionsebenen wie z.B. Wrapper-Klassen oder Bibliotheken für die Übersetzung von Schlüsselwörtern in Abfolgen von Aktionen notwendig. Weiterhin ist Disziplin der Tester notwendig, um nicht für schnell benötigte Lösungen die höhere Abstraktionsebene zu verlassen und schwer wartbare Testskripte zu schaffen. Die verwendeten Modellierungsframeworks hingegen zwingen die Tester zum Verbleib auf der Modellierungsebene und sorgen somit für eine dauerhafte, verbesserte Wartbarkeit. Weiterhin bieten Frameworks wie xText die Möglichkeit, komfortable Editoren allein aus der Sprachbeschreibung zu generieren.

Modellbasierte Testautomatisierung

Der modellbasierte Testentwurf nutzt Modelle als Basis für den Testentwurf. Modelle sind abstrakte Beschreibungen von beliebigen Artefakten, die in unserem Fall für den Testentwurf genutzt werden sollen. Sie können das Systemverhalten definieren oder das Testverhalten. Sie können ein separates Testmodell oder Bestandteil eines gemeinsamen Test- und Entwicklungsmodells sein. Sie können (nicht-)deterministisch, zeitlos oder zeitbehaftet, diskret, kontinuierlich oder eine Mischung daraus sein. Sie können Datenfluss, Kontrollfluss oder eine Mischung davon beschreiben. Das Verhalten kann kontinuierlich oder ereignisgesteuert sein. Daraus ergibt sich in erster Konsequenz eine breite Vielfalt von Einsatzmöglichkeiten von allen möglichen Arten von Modellen für den Testentwurf.

Modelle können zum Beispiel genutzt werden, um nicht nur einzelne Testfälle auf abstrakter Ebene zu beschreiben, sondern auch, um ganze Mengen von Testfällen zu beschreiben. Das wird erreicht, indem Verzweigungen, bedingte Anweisungen, Reaktionen auf externe Ereignisse u.v.m. bereits auf Modellebene definiert wird. Ein Modell kann genutzt werden, um einen ganzheitlichen Überblick über das gesamte System und die wechselseitigen Abhängigkeiten zwischen Komponenten zu bekommen. Das hilft schon deutlich in früheren Phasen der Systementwicklung, z.B. während des Reviews von Anforderungen oder Architekturentwürfen. Aber natürlich werden hier auch alle testrelevanten Informationen gebündelt und aus ihrer Gesamtheit werden die Testfälle abgeleitet.

Wenn die Ableitung der Testfälle aus dem Modell automatisch geschieht, ergeben sich weitere Vorteile: Kleinere Änderungen im Modell, die sich aber auf eine Vielzahl von Testfällen beziehen, können automatisch in die Testfälle überführt werden. Der Testgenerator geht dabei oft so vor, dass bestimmte Qualitätsziele wie z.B. das Erreichen einer bestimmten Überdeckung auf Modellebene als Endekriterium für den Testentwurf gewählt werden. Damit können also auch Änderungen, die weitere Testschritte, eine geänderte Zahl an Parametern oder eine Änderung des erwarteten Verhaltens beinhalten, automatisch übernommen werden. Die entsprechenden Testfälle werden automatisch generiert.

Zustandsmaschine zum Werdegang von Testern

Zustandsmaschine zum Werdegang von Testern

Hier eine Beispiel eines Zustandsmodells. Es zeigt exemplarisch mögliche Übergänge im Werdegang eines Testers vom Testlehrling bis zum Testmeister. Natürlich bedarf es im Normalfall mehr als das Bestehen einer Prüfung, um ein Testmeister zu werden. Die Darstellungsform ähnelt denen der UML Zustandsmaschinen. Diese Zustandsmaschine lässt jeden Tester im Zustand „Testlehrling“ beginnen. Je nachdem, ob der Lehrling die Prüfung zum Certified Tester Foundation Level besteht, wird er danach als Testgeselle geführt oder kann die Prüfung wiederholen. Auf diese Weise kann er sich schrittweise bis zum Testmeister hocharbeiten.

Wollte man eine Anwendung testen, die die hier beschriebenen möglichen Karrierepfade beschreibt, so gäbe es einen direkten Testfall – den Gutfall, der beinhaltet, dass jede Prüfung auf Anhieb geschafft wird. Wenn man die Schlechtfälle mit einbezieht, dann zeigt bereits dieses kleine Beispiel, dass aufgrund der Zirkelschlüsse theoretisch unendlich viele Pfade möglich sind. Ein Testgenerator orientiert sich während der Testerzeugung meist nur an der Struktur des Modells. Wenn Zustände in diesem Modell hinzugefügt, geändert oder entfernt werden, so bezieht er diese bei einem neuerlichen automatischen Testentwurf automatisch mit ein.

Der wesentliche Vorteil gegenüber dem schlüsselwortgetriebenen Ansatz ist, dass nun der gesamte Ablauf mitsamt möglicher Verzweigungen, Schachtelungen, Schleifen oder parallelem Verhalten beschrieben und für den Testentwurf genutzt werden kann. Das Modell wird durch einen modellbasierten Testgenerator so interpretiert, dass einzelne kontrollflussbasierte Ablaufsequenzen durch dieses Modell erzeugt werden, die im Folgenden in ein zuvor definiertes Zielformat umgewandelt werden. Zu den gängigen Zielformaten gehören ausführbarer Testcode, die menschenlesbare Variante dessen z.B. für die Validierung, sowie die Testdokumentation. Zu den Vorteilen gehört entsprechend, dass auf jede Art von Änderung in der Modellebene oder den Exporten des zugehörigen Testgenerators reagiert werden kann. Die daraus resultierenden Testfälle werden im Anschluss daran automatisch generiert. Die hohe Gefahr der manuellen Anpassung einer Vielzahl von Testfällen mit dem dazugehörigen Aufwand wie bei den zuvor beschriebenen Varianten ist hier nicht mehr vorhanden. Dadurch wird eine starke Steigerung der Testeffizienz erreicht. Zu den Nachteilen gehört der hohe Vorbereitungsaufwand.

Vergleich der Testautomatisierungs-Arten

Ein qualitativer Vergleich auf Basis unserer Erfahrungen zeigt folgende Kosten-Struktur:


Capture & Replay

Skriptbasiert

Datengetrieben

Schlüsselwort-getrieben

Modellbasiert

Initiale Kosten

sehr niedrig

niedrig

niedrig

mittel

hoch

Wiederkehrende Kosten

sehr hoch

mittel

mittel

niedrig

sehr niedrig

Daraus ist schon ersichtlich, dass höhere Stufen der Testautomatisierung langfristig Kosten sparen, untere Stufen sich dafür besser für eine schnelle Einschätzung eignen. Generell sind bei der Wahl immer noch die Rahmenbedingungen zu beachten: Welches Projektvorgehen wird genutzt? Wer erstellt die Testfälle? Wieviel Kapazität steht bereit?

Mehr Anhaltspunkte zur Wahl der richtigen Strategie findest Du in meinem Buch Basiswissen Testautomatisierung.