Agile Modellierung mit
UML
Loading

8 Testmuster im Einsatz

Ergänzend zur Beschreibung der Theorie und der allgemeinen Vorgehensweise bei der Entwicklung von Tests wird in diesem Kapitel der Einsatz der UML/P anhand von Testmustern demonstriert. Mit diesen Mustern wird unter anderem die Definition von Dummies und von funktionalen Tests für nebenläufige und verteilte Systeme skizziert.

8.1 Dummies
8.1.1 Dummies für Schichten der Architektur
8.1.2 Dummies mit Gedächtnis
8.1.3 Sequenzdiagramm statt Gedächtnis
8.1.4 Abfangen von Seiteneffekten
8.2 Testbare Programme gestalten
8.2.1 Statische Variablen und Methoden
8.2.2 Seiteneffekte in Konstruktoren
8.2.3 Objekterzeugung
8.2.4 Vorgefertigte Frameworks und Komponenten
8.3 Behandlung der Zeit
8.3.1 Simulation der Zeit im Dummy
8.3.2 Variable Zeiteinstellung im Sequenzdiagramm
8.3.3 Muster zur Simulation von Zeit
8.3.4 Timer
8.4 Nebenläufigkeit mit Threads
8.4.1 Eigenes Scheduling
8.4.2 Sequenzdiagramm als Scheduling-Modell
8.4.3 Behandlung von Threads
8.4.4 Muster für die Behandlung von Threads
8.4.5 Probleme der erzwungenen Sequentialisierung
8.5 Verteilung und Kommunikation
8.5.1 Simulation der Verteilung
8.5.2 Simulation von Singletons
8.5.3 OCL-Bedingungen über mehrere Lokationen
8.5.4 Kommunikation simuliert verteilte Prozesse
8.5.5 Muster für Verteilung und Kommunikation
8.6 Zusammenfassung

Die Sammlung von Entwurfsmustern („Design Patterns“) [GHJV94] ist eine der ersten Arbeiten, die gezeigt hat, dass in Softwareentwicklungsprojekten erprobte Strukturen und Techniken herausgearbeitet, dokumentiert und dadurch wiederverwendet werden können. Auch für Testzwecke lassen sich allgemein gültige und themenspezifische Muster identifizieren. In diesem Abschnitt werden einige Testmuster exemplarisch beschrieben, um damit zu zeigen, wie die UML/P zur Umsetzung solcher Testmuster verwendet werden kann. Die hier behandelten Testmuster konzentrieren sich auf die Themen:

  • Dummies1,
  • Gestaltung testbarer Programme in Bezug auf die Verwendung statischer Variablen, Objekterzeugung und die Verwendung vorgefertigter Frameworks,
  • Simulation von Zeit,
  • Nebenläufigkeit,
  • Verteilung und Kommunikation.

Diese Testmuster dienen vor allem der Präparation des Testlings und dessen Umgebung, so dass damit effektiv Tests der Funktionalität durchgeführt werden können. Dummies dienen zum Beispiel zur Simulation der Umgebung des Testlings und fangen Seiteneffekte ab oder stellen vorgefertigte Aufrufergebnisse bereit.

Die in den Testmustern behandelten Konzepte können auch nachträglich in bereits vorhandene Software eingebracht werden. Dazu eignet sich die in Kapitel 10 diskutierte Einbettung dieser Testmuster in entsprechende Regeln für das Refactoring von Modellen für den Einbau der Testmuster.

Eine empfehlenswerte Sammlung an Testmustern, die Tests von einzelnen Methoden bis zu vollständigen Systemen diskutiert, ist in [Bin99] enthalten. Darin wurden zum Beispiel Teststrategien für die Überdeckung von Kontrollflüssen, Integrations- oder Regressionstests diskutiert. Ergänzend dazu behandelt [LF02] eher technologiespezifische Themen wie Persistenz mithilfe von Datenbanken, Kommunikation unter Zuhilfenahme von CORBA [OH98], die Verwendung von Frameworks wie Enterprise JavaBeans [MH00] oder Technologien wie Java Server Pages [FK00]. Der Verbesserung des Testprozesses widmet sich [PKS02]. Dabei werden Checklisten genutzt, um beispielsweise eine projektspezifische Optimierung des Testprozesses zu erreichen.

Ein Testmuster ist in Analogie zu den Entwurfsmustern in [GHJV94], eine generische Beschreibung eines wiederkehrenden Entwurfsproblems, das speziell die Testbarkeit des Systems unterstützt. Dabei wird auf die Vorgehensweise zur Durchführung von Tests, auf die dabei notwendigen strukturellen Veränderungen des zu testenden Codes und die Strategie der Testdurchführung eingegangen. Weil jedoch diese Strategie im Sinne einer agilen Methodik vor allem durch den Test-First-Ansatz (siehe Abschnitt 2.3.2 und [Rum04]) getrieben wird, liegt bei diesen Testmustern im Gegensatz zu [Bin99] der Fokus vor allem auf der Unterstützung der Durchführung effektiver Tests. Dabei wird konsequent eine Systemarchitektur gefordert, die sich für Tests eignet, und diskutiert, wie diese auch bei vorgefertigten Frameworks und Komponenten umgesetzt werden kann. Dass ein System so entworfen werden sollte, dass es für Tests kontrollierbar und beobachtbar ist, setzt sich erst langsam durch [Bin94HBG01].

Ein Teil dieses Kapitels ist dem funktionalen Test verteilter Systeme gewidmet, die intern und mit der Umgebung asynchron kommunizieren oder mehrere nebenläufige Threads besitzen. Es ergänzt damit die bereits genannten Testmustersammlungen. Verteilte Systeme sind inhärent nichtdeterministisch. Zum Beispiel wird die Verarbeitung von Nutzereingaben aus der Oberfläche aus Gründen der besseren Reaktivität durch verschiedene Threads gehandhabt. Ebenso werden Internet-Anfragen nebenläufig bearbeitet, so dass heute nahezu in jedem System Nebenläufigkeit auftritt. Auch das Auktionssystem ist durch das Internet auf viele Clients und Server verteilt, besitzt aber auch innerhalb jedes dieser Systemteile mehrere Threads.

Für automatisierte Tests sind nichtdeterministische Abläufe grundsätzlich kritisch, da sie die Bewertbarkeit des Ergebnisses erschweren. Durch Verwendung von OCL-Bedingungen zur Überprüfung des Testerfolgs, die eine gewisse Bandbreite zulassen, ist es prinzipiell möglich, mit nichtdeterministischen Ergebnissen bei Testabläufen umzugehen. Jedoch geht ein wesentliches Kriterium für automatisierte Tests, die Wiederholbarkeit, verloren. Ein nur sporadisches Scheitern eines Tests kann vom Entwickler oft nur schwer nachvollzogen werden und macht die Behebung des Fehlers schwierig.

Für funktionale Tests ist es deshalb sinnvoll, nichtdeterministische Effekte vollständig zu unterbinden. Dies kann durch geschickte Verwendung von Dummies sowie durch die explizite Festlegung an sich paralleler Abläufe durch ein kontrolliertes Scheduling erfolgen und wird in den nachfolgenden Abschnitten erörtert.

Die Systematik zur Vorstellung von Mustern, wie sie in [GHJV94] eingeführt und seitdem für viele Musterarten fortgeführt wurde, kann auch für Testmuster eingesetzt werden und wird in diesem Abschnitt vereinzelt angewandt. Dabei wird nur eine Teilmenge des Schemas aus [Bin99] verwendet, da diese Technik vor allem zusammenfassend am Ende einer Diskussion eingesetzt wird.

Der Abschnitt 8.1 diskutiert die Einführung von Dummies zur Definition der Umgebung eines Testlings. Abschnitt 8.2 beschreibt generelle, sich aus der zugrunde liegenden Sprache ergebende Probleme beim Testen objektorientierter Systeme und gibt Richtlinien zur Strukturierung des Produktionssystems, so dass dieses für Tests besser zugänglich ist. Dazu gehören zum Beispiel die Kapselung statischer Variablen und die Dynamisierung der Objekterzeugung durch das Factory-Entwurfsmuster. In Abschnitt 8.3 wird die Simulation von Zeit in einem funktionalen, wiederholbaren und damit auf Determiniertheit ausgerichteten Test diskutiert. Die Abschnitte 8.4 und 8.5 behandeln Nebenläufigkeit, Verteilung und Kommunikationsaspekte, die die Definition funktionaler Tests über die Grenzen einzelner Prozesse hinaus erschweren. Es werden mehrere Testmuster eingeführt, die die Testbarkeit funktionaler Eigenschaften solcher Systeme signifikant verbessern beziehungsweise erst ermöglichen.


Bernhard Rumpe. Agile Modellierung mit UML. Springer 2012