Testautomatisierung mit der Test Workbench

Testgetriebene Entwicklung gehört bei n-design zum Alltag. Hierbei kommt die übliche Toolchain bestehend aus JUnit, Maven (Surefire Plugin) und Jenkins zum Einsatz. Damit erreichen wir eine hohe Testabdeckung im Bereich der Komponententests und können eine großen Teil von Integrationstests umsetzen.

Für die Durchführung von Systemtests kommen zusätzlich unterschiedliche Werkzeuge, z.B. Selenium für Web-GUI-Tests oder SOAP-UI für WebServices, zum Einsatz. Diese eher lose Tool-Sammlung ist für eine begrenzte Menge an explorativen Tests und seltene Deployments beherrschbar. Das wird allerdings schnell anders, wenn die Zahl der Tests steigt und diese häufig oder regelmäßig ausgeführt werden sollen.

Im Rahmen der Entwicklung einer dezentralen Komponente der Telematikinfrastruktur der gematik, die wir bei n-design betreiben, müssen hohe Anforderungen an Systemtests erfüllt werden, so dass wir dringend eine Lösung zur Testautomatisierung finden mussten.

Entwicklung einer eigenen Testautomatisierung

Am Markt sind einige Produkte zur Testautomatisierung verfügbar, die wir entsprechend unserer Anforderungen betrachtet haben. Insbesondere das Test-Framework Citrus hat uns gut gefallen. Allerdings haben wir sehr spezifische Anforderungen bzgl. der Testfall-Definition und des Reportings zu erfüllen, so dass die Verwendung eines Standard-Tools mit hohem Aufwand für das Customizing einhergegangen wäre. Auch das Risiko bestimmte Anforderungen ggf. gar nicht umsetzen zu können, erschien uns letztlich größer als das einer Eigenentwicklung, zumal wir auf einige Projekterfahrung im Bereich Testautomatisierung zurückblicken können. Wir entschieden uns daher, ein eigenes Tool zur Testautomatisierung zu entwickeln.

Ziele der Test Workbench

Modularisierung von Ausführungsschritten – Testmodule

Ziel der Test Workbench ist, bei der Definition von Testfällen auf Programm Code im Sinne imperativer Programmierung zu verzichten. Ein Testfall besteht jedoch aus ausführbaren Komponenten. Diese zu programmierenden Komponenten werden daher in Module gekapselt und können für einen konkreten Testfall deklarative komponiert werden. Dies hat aus unserer Sicht mehrere Vorteile:

  • Die Wiederverwendung der programmatischen Teile wird vereinfacht.
  • Eine Arbeitsteilung zwischen Entwicklern und Testfall-Designern ist leichter möglich. Testfall-Designer müssen nicht zwingend Entwickler sein.
  • Module können in beliebiger Reihenfolge zu Ausführungssequenzen miteinander kombiniert werden.

Testmodule teilen sich dabei eine gemeinsame einfache Schnittstelle, über die jedes Modul die Ergebnisse der Vorgänger erhält und seine eigenen Ergebnisse zurückgibt.

Die folgende Abbildung zeigt eine einfache Ausführungssequenz von drei Testmodulen innerhalb eines Testfalls.

Neben der eigentlichen Ausführungs-Methode verfügt die Modul-Schnittstelle zusätzlich über eine Methode zum expliziten Beenden eines Moduls. Diese wird in umgekehrter Ausführungsreihenfolge aufgerufen und ermöglicht die Implementierung von Modulen mit z.B. Hintergrundaufgaben wie beispielsweise das Empfangen von Requests eines „system under test“.

Testfall-Definition in XML

Die Definition konkreter Testfälle soll in einer ersten Ausbaustufe in XML erfolgen. Alternative Repräsentationen, die ggf. zu einem späteren Zeitpunkt benötigt werden, sollen durch die Architektur berücksichtigt werden. Dementsprechend werden Mechanismen zum Laden einer Testfall-Definition abstrakt gehalten.

Alternative und multiple Reports

Für unterschiedliche Zielgruppen, sind verschiedene ggf. parallel zu erstellende Reports einer Testfallausführung notwendig. Dies sind zunächst die Reports für den Auftraggeber mit den eigentlichen Testergebnissen sowie die Reports für die Softwareentwickler mit detaillierten Hinweisen auf Fehlerursachen. Bei der Erfüllung dieser Anforderung war daher zu beachten, einerseits die Schnittstelle für das Reporting generisch zu halten und anderseits die Konfiguration für den Report in den Testfällen logisch von der Ausführungskonfiguration zu trennen.

Abstrakte Kriterien für die Ausführungssteuerung

Um ein Set an Testfällen auszuführen werden mehrere Komponenten unterschiedlicher Ebene ausgeführt:

  • Testmodule – Sie kapseln ausführbaren Programm-Code in Modulen für einen Testfall.
  • Testfall – Besteht aus einer Komposition mehrerer Testmodule.
  • Testgruppe – Ist eine Sequenz von Testfällen
  • Testlauf – Die Ausführung aller Testfälle und -gruppen ist ein Testlauf.

Dabei kann jede Komponente auf den unterschiedlichen Ausführungsebenen mit einem von vier Zuständen terminieren:

  1. Erfolgreich – Test(schritt) entspricht Erwartungen
  2. Nicht Erfolgreich – Test(schritt) entspricht nicht Erwartungen
  3. Abbruch – nicht erheblicher Fehler
  4. Ausnahme – gravierender Fehler

In Abhängigkeit dieser vier Zustände entscheiden Steuerungseinheiten auf jeder Ebene über die Ausführung nachfolgender Komponenten. Durch die abstrakte Definition der Ausführungsbedingungen für die Schnittstellen der Steuerungseinheiten sind unterschiedliche Implementierungen der Ausführungslogik möglich.

So kann beispielsweise eine Implementierung zur Steuerung der Testfall-Ausführung vorsehen, dass bei jedem nicht erfolgreichen Testmodul der Testfall abgebrochen wird. Eine andere Umsetzung könnte zwischen Modulen für Vor- und Nachbedingungen unterscheiden und damit eine komplexere Steuerung
vorsehen.

Konkreter Testfall – Smart Card Version lesen

Das folgende Beispiel zeigt einen Testfall für ein System, in dem Smart Cards verwendet werden. Geprüft wird hierbei, ob eine verfügbare Karte eine erwartete Version hat.

Voraussetzung für den Testfall ist, dass das System entsprechend konfiguriert und eine gesteckte Smart Card vorhanden ist.

Das „system under test“ verfügt über eine JSON- und eine SOAP-Schnittstelle. Über die JSON-Schnittstelle wird im Testfall zunächst die passende Konfiguration geladen. Dann wird über die SOAP-Schnittstelle die die Abfrage über die verfügbare Karte gestartet.

Anschließend wird das Ergebnis mit einem Extractor aus der SOAP-Response herausgelöst. Ein weiterer möglicher Schritt in diesem Beispiel wäre die Überprüfung einer speziellen Kartenversion mit einem dafür geeigneten Validator-Modul.

Dieses Beispiel illustriert die Komposition verschiedener Testmodule in unterschiedlichen Rollen. Während das Laden der Konfiguration im Kontext einer Vorbedingung steht, ist die Abfrage der Kartenversion Bestandteil der Prüfung einer Erwartungshaltung. Dementsprechend unterscheidet die Ausführungssteuerung zwischen dem Scheitern eines Moduls in Vorbedingungen und anderen Modulen. So kann z.B. beim Fehlschlag der Vorbedingung der gesamte Testlauf abgebrochen werden.

In der beispielhaften Testfallbeschreibung werden Variablen verwendet, z.B.   ${ip.adress} . Dabei können Variablen statisch definiert werden oder mit Werten aus den Ergebnissen der Testmodule belegt werden.

Für das dynamische Reporting von Testergebnissen können Module über Report-Items ihre Ergebnisse an die Report-Schnittstelle geben.

Fazit & Ausblick

Eigene Entwicklung

Die eigene Entwicklung der Test Workbench ist aus unserer Sicht ein lohnenswerter Ansatz gewesen. Der größte Aufwand bei der Entwicklung lag bisher in der Implementierung von Testmodulen für konkrete Testfälle. Ablaufsteuerung und Reporting sowie weitere Infrastruktur-Komponenten haben also bezogen auf die Gesamtaufwände eine untergeordnete Rolle gespielt. Bei der Verwendung eines bereits vorhandenen Frameworks hätten Aufruf und Evaluierung von Schnittstellen des „system under test“ ebenfalls implementiert werden müssen. Dieser Aufwand entsteht also in jedem Fall.

Komplexität von Testfallbeschreibungen vs. spezialisierte Testmodule

Interessant ist aus unserer Sicht auch die Balance zwischen Aufwand bei der Testmodul-Entwicklung und der Komplexität konkreter Testfallbeschreibungen. Wird der Testfall durch eine Vielzahl einfacher, generischer Module abgebildet oder lohnt die Entwicklung eines aufwendigeren, spezialisierten Moduls? Die Frage entscheidet sich in der Regel an der Menge ähnlicher Testfälle. Kann die Komplexität sehr vieler Testfälle durch die Entwicklung eines komplexen Testmoduls reduziert werden, so entscheiden wir uns für die Modul-Entwicklung. Auch diesbezüglich ermöglicht unsere individuelle Entwicklung den größtmöglichen Freiheitsgrad bei dieser Abwägung.

Abstrakte Komponenten

Die Abstraktionen bezüglich Reporting, Testfall-Definition und Ausführungssteuerung haben sich bereits ausgezahlt, da wir für die drei Bereiche tatsächlich innerhalb kurzer Zeit alternative Implementierungen benötigten. Durch diese Anpassbarkeit ist die Test Workbench auch für unsere Kunden interessant, da von der Testfallbeschreibung bis zum Report individuelle Anforderungen umgesetzt werden können, ohne den Kern der Anwendung zu berühren.

Weitere Entwicklung

Bezüglich weiterer Ausbaustufen der Test Workbench werden im Entwicklerteam bereits einige Ideen gehandelt:

  • GUI für grafische Komposition von Testmodulen
  • GUI zur Verwaltung von Testfällen
  • Dashboard für die dynamische Beobachtung eines Testlaufs
  • Analyse-Tools für die Testergebnisse

Wenn es eine Aufgabe erfordert und die Umsetzung im konkreten Kontext rentabel ist, freuen wir uns auf diese Weiterentwicklungen.