Oct 032008
 

Durch zeitgesteuerte Aktionen kann ein Softwaresysteme bestimmte Anforderungen umsetzen. Zum Beispiel könnte eine Anforderung sein, dass eine Applikation jede Nacht bestimmte Datenbereinigungen durchführt. Bei OpenWishes prüfen wir beispielsweise periodisch, ob Geburtstagserinnerungen per E-Mail versendet werden müssen. Dies sind natürlich nur triviale Beispiele. Der Faktor Zeit kann nicht nur Aktionen auslösen, sondern auch das Verhalten von Geschäftslogik beeinflußen. Beispielsweise kann der Kunde im Support-Portal nach Ablauf der Garantiezeit eines gekauften Artikels keinen Reklamationsvorgang mehr einleiten.

Leider lassen sich solche zeitgesteuerten Aktionen und Geschäftslogik nicht ohne Weiteres einfach testen. Bei der Durchführung des Tests kann nur in Ausnahmefällen die reale Zeit abgewartet werden, um die zeitabhängige Logik zu verifizieren.

Ein Weg diese Tests zu ermöglichen ist die Manipulation von gespeicherten Zeitstempeln. Im Beispiel der Artikelreklamation kann das Kaufdatum des Artikels geändert werden um zu prüfen, dass kein Reklamationsvorgang nach Ablauf der Garantie einleitetbar ist. Dieser Weg ist jedoch nicht in allen Situationen möglich und zudem für jedes zu testende Szenario unterschiedlich.

Zeitmaniupalation für Tests

Eine bessere Lösung ist, die Zeit in welchem das Softwaresystem lebt, generell zu manipulieren. Warum also nicht die Zeit um 2 Jahre für das System nach vorn drehen und direkt verifizieren, dass kein Reklamationsvorgang möglich ist. Die Manipulation der Zeit im Betriebssystem ist in vielen Situationen nicht praktikabel, da das Betriebssystem weitere Programme ausführt, die nicht beeinflußt werden sollen. Ein anderer Faktor sind fehlende Rechte für das Verändern der Zeit im Betriebssystem. Treffen diese Faktoren nicht zu, so beeinflußt das ändern der Aktuellen Betriebssystemzeit eine aktuell laufende JVM (geprüft unter Windows XP SP2 und Java 1.6).

Eine Java Applikation kann die aktuelle Systemzeit nur über API-Methoden des JDK wie new Date() und System.currentTimeMillis() ermitteln (vom Aufruf nativen Codes über JNI einmal abgesehen) .

Realisierung unserer Zeitmaschine

AspectJ ermöglicht das Abfangen von Aufrufen an API-Methoden des JDK, welche die aktuelle Zeit / das aktuelle Datum liefern. Damit wird ein Mechanismus implementiert, mit dem zur Laufzeit die aktuelle Zeit verändert werden kann.

Folgende Singleton-Klasse dient zur Speicherung des Offsets zur tatsächlichen aktuellen Zeit:


Ein Aspekt fängt alle relevanten JDK-API-Aufrufe ab und verwendet den in TimeSimulationOffset gespeicherten Zeit-Maniuplation-Offset:


Zu Beachten

Falls unsere zu testende Applikation mit anderen Systemen kommuniziert, so ist ggf. darauf zu achten, dass die Zeit in der anderen Applikation analog manipuliert wird. Oft ist die zeitliche Synchronität für die Anbindung anderer Systeme nicht für die betrachteten Testszenarien relevant. Somit ist dieser Punkt nur selten zu bedenken.

Eher wahrscheinlich ist, dass unsere Applikation zusätzliche JAR-Bibliotheken verwendet, welche ebenso mit der aktuellen Systemzeit arbeiten. Wahrscheinlich beeinflußt die Systemzeit die durch die Bibiliothek bereitgestellte Funktionalität ohne dass dies eine Auswirkung auf das Resultat des Testszenarios hat. Zum Beispiel wird für Logging-Bibliotheken wie “log4j” die Systemzeit lediglich in die Logausgabe geschrieben. Dies hat jedoch keinen Einfluß auf das fachliche Verhalten der Applikation.

Falls dennoch erforderlich, so können die Class-Dateien im entsprechenden JAR mit AspectJ angepasst werden. Der TimeSimulation-Aspekt wird in das JAR verwebt, so dass die Bibliothek ebenfalls die manipulierte Zeit verwendet.

Test

Wer Zweifel hat, dass das ganze funktioniert, sollte diesen Unit-Test ausführen. Ich habe das Ganze in
einem Eclipse Java-Project ausgeführt bei dem AspectJ-Capabilities aktiviert sind.


Fazit

Durch diese einfache und umfassende Lösung ist es möglich, zeitabhängige Logik mit geringem Aufwand zu testen. Ein wesentlicher Vorteil ist der geringe Eingriff in den Quellcode der Applikation.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>