Übersicht Inhaltsverzeichnis Vorwort 1 Einführung 2 Agile und UML-basierte Methodik 3 Kompakte Übersicht zur UML/P 4 Prinzipien der Codegenerierung 5 Transformationen für die Codegenerierung 6 Grundlagen des Testens 7 Modellbasierte Tests 8 Testmuster im Einsatz 8.1 Dummies 8.2 Testbare Programme gestalten 8.3 Behandlung der Zeit 8.4 Nebenläufigkeit mit Threads 8.5 Verteilung und Kommunikation 8.6 Zusammenfassung 9 Refactoring als Modelltransformation 10 Refactoring von Modellen 11 Zusammenfassung und Ausblick Literatur |
8.3 Behandlung der ZeitIn verteilten Echtzeitsystemen spielt die kontinuierlich voranschreitende Zeit eine wesentliche Rolle. Im Auktionssystem wird zum Beispiel anhand der aktuellen Zeit entschieden, in welchen Zustand eine Auktion übergehen soll, ob ein Gebot angenommen oder abgelehnt wird oder ob Mitteilungen an die Bieter versandt werden. In Java kann mit System.currentTimeMillis() die aktuelle Zeit in Form von Millisekunden ermittelt werden. Je nach Laufzeit eines Tests werden so auch innerhalb eines Tests unterschiedliche Zeiten und Zeitdifferenzen gemessen, die das Testergebnis beeinflussen. Beispielsweise differiert dann bereits die Protokollausgabe in Abhängigkeit des Zeitraums, in dem ein Test ausgeführt wird. Durch die Einbeziehung der aktuellen Zeit geht die in Kapitel 6 geforderte Determiniertheit des Testablaufs verloren. Deshalb ist es notwendig, die während des Testablaufs herrschende Zeit durch den Testtreiber zu kontrollieren. Als Nebeneffekt können damit auch Tests, die sich in der echten Zeitrechnung über mehrere Stunden hinziehen, wie etwa eine gesamte Auktion, effektiv in Sekundenbruchteilen durchgeführt werden. 8.3.1 Simulation der Zeit im DummyAufgrund der genannten Überlegungen wird die Abfrage nach der Zeit in einer eigenen Klasse konzentriert und durch ein voreinstellbares Dummy-Objekt kontrollierbar gemacht. Abbildung 8.13 beschreibt diese Konstruktion mit Ausschnitten der Dummy-Klasse. Im Auktionsprojekt wurde zusätzlich das Muster für Singletons hinter statischen Methoden aus Tabelle 8.9 angewandt.
Die Funktion setTime erlaubt es Testtreibern, die Zeit beliebig zu besetzen. Allerdings bleibt während der Durchführung eines Tests die Zeit konstant. Dies entspricht einer idealisierenden Annahme, dass während der Berechnung einer Reaktion keine tatsächliche Zeit vergeht, die zum Beispiel in Sprachen für eingebettete Systeme wie Esterel [Hal93] angewandt wird. Tatsächlich fordert das vorgeschlagene Testmuster Einschränkungen bezüglich der Verwendung der angeforderten Zeit. Idealerweise sollte nur eine Zeitanfrage stattfinden, die dann als Referenzzeit während der Berechnung genutzt wird. Sollte es notwendig sein, dass innerhalb des Rumpfs einer Methode die Zeit voranschreitet, so kann durch Aufruf von incTime() bei jeder Anfrage von now() ein Voranschreiten simuliert werden. 8.3.2 Variable Zeiteinstellung im SequenzdiagrammParallel zum Einsatz der Zeitsimulation kann ein Sequenzdiagramm genutzt werden, um die Uhr für jeden neuen Aufruf des Testlings umzustellen. Beispielsweise kann das Sequenzdiagramm aus Abbildung 7.12 so erweitert werden, dass die Zeit jeweils explizit gesetzt wird. Es entsteht das Sequenzdiagramm aus Abbildung 8.14. Durch die Verwendung von Merkmalen für Methodenaufrufe lassen sich diese Zeitangaben kompakter modellieren. Im Testsystem werden diese zeitlichen Merkmale konstruktiv interpretiert, indem sie nicht gemessen, sondern als Vorgabe für die jeweils gültige Systemzeit verwendet werden. Damit lässt sich eine mit Systemzeiten annotierte Form eines Auktionsablaufs in Abbildung 8.15 darstellen. Die Instrumentierung des Testlings für die Beobachtung von Methodenaufrufen und Returns erlaubt damit gleichzeitig die Anpassung der jeweils aktuellen Zeit. Tabelle 8.16 beschreibt die Anwendung des Merkmals {time} und seiner additiven Form {time+}.
8.3.3 Muster zur Simulation von ZeitDas diskutierte Muster zur Behandlung der Zeitproblematik wird in Tabelle 8.17 zusammengefasst.
Eine Verfeinerung dieses Konzepts wurde im Auktionsprojekt eingesetzt, indem bei Testläufen mehrere Clients und der Server im gemeinsamen Prozessraum laufen. Da Clients unterschiedliche Systemzeiten besitzen sowie Signallaufzeiten im Internet nicht zu unterschätzen sind, wurde für jeden Client eine eigene Zeit simuliert, indem beim Wechsel der Aktivität zwischen Clients die Zeit jeweils umgesetzt wurde. Dazu wurde das in Abschnitt 8.5 besprochene Muster 8.25 eingesetzt. Damit lassen sich auch relativistische Phänomene modellieren und zum Beispiel die (notwendigerweise nur ungefähre und netzbedingt manchmal unzureichende) Zeitsynchronisation zwischen Clients und Server testen, denn eines der im Internet kritischen Probleme resultiert aus den signifikanten und teilweise sehr unterschiedlichen Signallaufzeiten, die sich bei einer Echtzeitanwendung, wie es beim Auktionssystem der Fall ist, bemerkbar macht. 8.3.4 TimerEng verwandt mit der Abfrage der aktuellen Zeit ist die Überwachung von Zeitüberschreitungen. Diese sind grundsätzlich mit denselben Prinzipien realisierbar. Typischerweise werden Timer für jede Aufgabe neu erzeugt, weshalb eine Timer-Factory als globales Singleton realisiert wird. Timeouts können so gezielt erwirkt oder verhindert und durch Timer oder direkt vom Testtreiber übermittelt werden.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||