Parallele Teststränge¶
sind Testschrittsequenzen, die zeitlich parallel (zur Hauptsequenz) ausgeführt werden
werden auch als nebenläufige Testfälle bezeichnet
können während ihrer Ausführung untereinander durch Austausch von Nachrichten kommunizieren
Start und Beendigung¶
Start
Der Start eines parallelen Teststranges erfolgt durch den parallelen (auch als asynchron bezeichneten) Aufruf eines Packages. Dies ermöglicht der Testschritt „Parallele Packagereferenz“.
„Parallele Packagereferenz“ wird analog zur klassischen Packagereferenz via Kontext-Menü-Befehl des Workspace-Explorers in den Testfall eingefügt.
Der klassische Package-Aufruf wird auch als synchroner Aufruf bezeichnet.
Wie beim synchronen Aufruf können dem aufgerufenen Package Parameter übergeben werden und die Zielvariablen im Aufrufer definiert werden, in die die Rückgabewerte des aufgerufenen Packages geschrieben werden.
Laufzeit und Beendigung
Asynchron aufgerufene Packages enden:
nach Ausführung ihres letzten Testschritts, der durch den Kontrollfluss bestimmt ist
nach Ausführung des Testschrittes Return
bei Testabbruch
Asynchron aufgerufe Packages können nicht gewaltsam (durch den Aufrufer) abgebrochen werden (außer durch einen Testabbruch), sie beenden sich immer selber. Ihnen kann aber eine Aufforderung zur Beendigung geschickt werden (siehe dazu Nachrichtenaustausch zwischen parallelen Teststrängen).
Beachte: Hat ein asynchron aufgerufenes Package seinerseits parallele Subpackages gestartet, so wartet es außer im Fall c) nach Ausführung seines letzten Testschritts auf das Ende aller Subpackages, bevor es zurückkehrt. D. h. parallel ausgeführte Subpackages leben niemals länger als das übergeordnete Eltern-Package. Dieses Verhalten wird als impliziter Join eines Packages mit seinen Subpackages bezeichnet.
Synchronisation und Zugriff auf Rückgabewerte eines asynchron aufgerufenen Packages
Die Rückgabewerte eines Packages stehen erst am Ende seiner Ausführung zur Verfügung und werden auch erst dann in die Zielvariablen des Aufrufers eingetragen. Der Aufrufer eines parallelen Packages muss also auf dessen Ende warten, bevor er auf dessen Rückgabewerte zugreifen kann. Dies geschieht automatisch, sobald ein Testschritt des Aufrufers lesend auf eine der Zielvariablen zugreift oder bei der automatischen Zwischenspeicherung aller Werte für die Traceanalyse im Rahmen des Stop Trace Testschritts. Der Lesezugriff blockiert dann den Aufrufer bis zum Ende des Subpackages (auch als expliziter Join eines Packages mit seinem Subpackage bezeichnet).
Der Schreibzugriff auf eine Zielvariable schlägt fehl, solange die asynchrone Ausführung des Subpackages noch nicht abgeschlossen ist. Gleiches gilt für die erneute Zuordnung einer Zielvariablen in einem zweiten asynchronen Aufruf, wenn der erste Aufruf noch nicht beendet ist.
Reporting¶
Die Darstellung asynchroner Aufrufe von Packages im Testreport geschieht auf gleiche Weise wie die des synchronen. Die farbliche Kennzeichnung der Aufrufe ist jedoch unterschiedlich. Desweiteren können parallel ausgeführte Subpackages aufgrund ihrer zeitlichen Überlappung mit ihrem Eltern-Package nicht inline (d. h. verschränkt mit den Testschritten des Eltern-Package) dargestellt werden.
Nachrichtenaustausch zwischen parallelen Packages¶
Parallele Packages können untereinander Nachrichten austauschen. Nachrichten können beliebige Python-Objekte (Zahlen, Zeichenketten etc.) darstellen. Zum Versenden von Nachrichten benötigt ein Package so genannte Outboxen, zum Empfangen entsprechend Inboxen. Dabei handelt es sich um spezielle Variablen, die im Variablen-Container eines Packages angelegt werden können. Die Verknüpfung von In- und Outboxen zu unidirektionalen Kommunikationskanälen geschieht im Dialog des „Parallele Packagereferenz“ Testschrittes analog der Parameter- und Rückgabewertzuordnung. Das Versenden und Empfangen von Nachrichten geschieht schließlich über die Testschritte „Aus Inbox lesen“ und „In Outbox schreiben“.
Outbox und Testschritt „In Outbox schreiben“¶
Eine Outbox ist der Endpunkt des unidirektionalen Kommunikationskanals zwischen zwei parallelen Packages auf Senderseite. Outboxen können wie gewöhnliche Variablen über den Variablen-Manager dem Package hinzugefügt werden. Die Option Nachrichten verwerfen, wenn nicht verbunden ist dann relevant, wenn versucht wird, Nachrichten über eine Outbox zu versenden, die mit KEINER Inbox verbunden ist. Bei deaktivierter Option (Standard) erzeugt dies einen Fehler. Ist die Option aktiviert, gehen die zu sendenden Nachrichten ohne Fehlermeldung verloren.
Besonders zu beachten ist auch die Kennzeichnung einer Outbox als OUT-Parameter über den entsprechenden Haken im Variablen-Manager. Diese bestimmt die Verschaltungsmöglichkeiten (siehe Kapitel Relays).
Das Versenden von Nachrichten erfolgt über den Testschritt In Outbox schreiben. Dieser ist auf dem Tab Testschritte in der Kategorie Datenoperationen zu finden. Im Feld Outbox ist die betreffende Outbox einzugeben bzw. auszuwählen. Im Feld Message kann ein beliebiger Python-Ausdruck eingeben werden, dessen Auswerte-Ergebnis dann bei der Ausführung als Nachricht versendet wird.
Beachte: Das Nachrichtenversenden ist nur über den Testschritt In Outbox schreiben möglich. Eine gewöhnliche Zuweisung an eine Outbox-Variable ist nicht möglich.
Inbox und „Aus Inbox lesen“¶
Die Inbox stellt den empfängerseitigen Endpunkt eines Kommunikationskanals zwischen zwei parallelen Packages dar. Sie arbeitet nach dem FIFO-Prinzip: Nachrichten, die zuerst in der Inbox ankommen, werden beim Abholen auch zuerst ausgeliefert. Inboxen können wie gewöhnliche Variablen über den Variablen-Manager dem Package hinzugefügt werden. Inboxen besitzen die folgenden, spezifischen Parameter:
Größe: Anzahl der Nachrichten, die die Inbox puffern kann, ohne überzulaufen.
Standard-Time-out: Standard-Zeit in Millisekunden für das Warten auf Nachrichteneingang bei Abfrage einer leeren Inbox. Nach Ablauf der Wartezeit ohne Nachrichteneingang liefert die Abfrage ~Not Present~ zurück. Die Standard-Wartezeit kann im Testschritt Aus Inbox lesen überschrieben werden.
Die beiden Optionen der Inbox bestimmen deren Verhalten bei Überlauf. Eine Inbox läuft genau dann über, wenn die Zahl der zu puffernden Nachrichten die Größe der Inbox übersteigt. Ist die Option Bei Größenüberlauf älteste Nachricht(en) löschen aktiviert, werden bei Ankunft neuer Nachrichten genau so viele der ältesten gelöscht, dass die Inbox beim Speichern der neuen gerade nicht überläuft. Ist zusätzlich die Option Größenüberlauf melden aktiv, wird beim Verwerfen alter Nachrichten eine entsprechende Warnung auf die Konsole ausgegeben. Ist jedoch ausschließlich die Option Größenüberlauf melden aktiv, wird ebenfalls eine Warnung ausgegeben. Aber in diesem Fall gehen die Nachrichten nicht verloren, sondern die Größe der Inbox wächst über ihr eingestelltes Limit hinaus, so dass auch die neu eintreffenden Nachrichten noch gepuffert werden können. Ist hingegen keine der beiden Optionen aktiv, scheitert das Ausliefern von Nachrichten an eine volle Inbox mit einem harten Fehler.
Tipp: Mit Größe 1 und Option Bei Größenüberlauf älteste Nachricht(en) löschen
lässt sich eine Art „Live-Rückgabewert“ realisieren, der sofort im Aufrufer-Package zur Verfügung steht und
fortlaufend durch das parallele Package aktualisiert wird.
Beim Konfigurieren einer Inbox besonders zu beachten ist auch die Kennzeichnung als IN-Parameter über den entsprechenden Haken im Variablen-Manager. Diese bestimmt die Verschaltungsmöglichkeiten (siehe Kapitel Relays).
Das Abholen von Nachrichten aus einer Inbox geschieht über den Testschritt Aus Inbox lesen. Dieser ist in der Kategorie Datenoperationen auf dem Tab Testschritte zu finden. Der Testschritt kennt zwei Modi: Abholen und Nachschauen. Im Modus Abholen wird die älteste Nachricht aus der Inbox entnommen, bei Nachschauen verbleibt die Nachricht in der Inbox. Der Modus Nachschauen wird mit der Option Nachricht in Inbox belassen aktiviert (Achtung: Werden alte Nachrichten nicht entnommen, kann man auf die neueren Nachrichten nicht zugreifen und die Inbox droht u. U. überzulaufen).
Neben Eingabe bzw. Auswahl der betreffenden Inbox gestattet der Testschritt auch noch die Angabe einer Wartezeit (in Millisekunden) für das Warten auf Nachrichteneingang bei leerer Inbox. Nach Ablauf der Wartezeit liefert die Abfrage ~Not Present~ zurück. Optionen für die Wartezeit sind Standard-Time-out (wie in der Inbox-Variablen parametriert), Unbegrenztes Time-out, sowie eine für den jeweiligen Aus Inbox lesen-Testschritt spezielle Wartezeit.
Desweiteren bietet der Testschritt Einstellungen zum Bewerten und Speichern der abgefragten Nachricht, analog den Einstellungen des Lesen- oder Berechnen-Testschritts.
Beachte: Das Abholen von Nachrichten ist nur über den Testschritt „Aus Inbox lesen“ möglich. Eine gewöhnlicher Lesezugriff auf die Inboxvariable (z.B. durch Verwendung in einem Python-Ausdruck) führt zu Fehlern.
Verknüpfung von Out- und Inboxen¶
Damit Nachrichten, die über eine Outbox verschickt werden sollen, auch an eine Inbox ausgeliefert werden, muss die Outbox (vor dem Senden) mit einer Inbox verknüpft werden. Dies geschieht auf dem Tab In-/Outboxen des Bearbeiten-Dialogs zum Testschritt Parallele Package Referenz. In der linken Spalte werden jeweils die In- und Outboxen des aufgerufenen Packages dargestellt. In der rechten Spalten können per Drop-Down-Menü die Out- und Inboxen des Aufrufers ausgewählt und zugeordnet werden.
Damit die Inboxen des aufgerufenen Packages auf der linken Seite angezeigt werden, muss Option IN-Parameter aktiviert sein. Analoges gilt für die Outboxen des aufgerufenen Packages. Sollen diese auf der linken Seite angezeigt werden muss die Option OUT-Parameter aktiviert sein.
Für die zuzuordnenden In- und Outboxen im Aufrufer gilt: Damit diese in der Auswahlliste erscheinen, dürfen die Optionen IN- und OUT-Parameter nicht aktiviert sein. Verletzt man die genannten Bedingungen durch nachträgliches Aktivieren bzw. Deaktivieren der IN-/OUT-Parameter-Kennzeichnung, kommt es zu Laufzeitfehlern.
Hintergrund dieser strikten Festlegung ist, dass die IN-/OUT-Parameter-Kennzeichnung die jeweiligen In-/Outboxen zu Schnittstellen des jeweiligen Packages deklariert, deren Verschaltung dem Aufrufer obliegt. Der Versuch einer Verschaltung durch das aufgerufene Package würde unweigerlich zu einem Fehler führen, da die Boxen zu diesem Zeitpunkt ja bereits in Benutzung sind.
Beachte: Eine Outbox kann immer nur mit genau einer Inbox verknüpft werden und umgekehrt (wird durch den Parametrierungs-Dialog sichergestellt). Die Wiederverwendung von Out- und Inboxen in weiteren asynchronen Package-Aufrufen ist möglich. Das parallele Package muss jedoch bereits beendet sein, bevor die In-/Outbox in einem erneuten Aufruf an ein weiteres paralleles Package geknüpft werden kann. Andernfalls kommt es zu einem Laufzeitfehler.
Relays - Nachrichtenaustausch zwischen parallelen Subpackages¶
Bisher wurde nur die direkte Verschaltung von In- und Outboxen betrachtet. Damit lassen sich jedoch ausschließlich Kommunkationskanäle zwischen dem Aufrufer und dem aufgerufenen Package etablieren. Für komplexere Kommunikationsstukturen werden Relays benötigt. Relays sind Verbindungsstücke, die zwei Enden zur Verschaltung besitzen, ein IN-Ende und ein OUT-Ende. Das IN-Ende kann mit einer Outbox, das OUT-Ende mit einer Inbox verknüpft werden. Alternativ können die Enden auch mit weiteren Relays verknüpft werden. Daraus ergeben sich mögliche Verknüpfungsstrukturen der folgenden Art:
Outbox–>IN-Relay-OUT–>Inbox,
Outbox–>IN-Relay1-OUT–>IN-Relay2-OUT–>Inbox
usw.
Soll z. B. zwischen zwei parallelen Subpackages S1 und S2 eines Hauptpackages H ein Nachrichtenaustausch stattfinden, so legt man im Hauptpackage ein Relay R(H), in Subpackage S1 eine Inbox In(S1) und in Subpackage S2 eine Outbox Out(S2) an. Beim Aufruf von S1 verknüpft man dessen Inbox In(S1) mit dem Relay R(H) und beim anschließenden Aufruf von S2 verknüpft man dessen Outbox Out(S2) ebenfalls mit dem Relay R(H). Damit ergibt sich schließlich die Struktur Out(S2) –> R(H) –> In(S1), so dass Subpackage S2 Nachrichten an Subpackage S1 schicken kann.
Relays sind wie In- und Outboxen spezielle Variablen, die dem Variablen-Container hinzugefügt werden können. Sie dienen ausschließlich der Nachrichtenweiterleitung, d. h. auf ihnen kann weder gelesen, noch geschrieben werden. Relays besitzen wie Inboxen einen Nachrichten-Puffer. Dieser dient dem Zwischenspeichern von Nachrichten, wenn das Relay bereits mit einer Outbox aber noch keiner Inbox verbunden ist und der Sender bereits Nachrichten verschickt. Die Größe des Nachrichtenpuffers ist im Einstellungsdialog der Variable konfigurierbar, ebenso das Verhalten, wenn der Puffer überläuft. Ist die Option Fehler bei Überlauf deaktiviert, wird nur eine Warnung auf der Konsole ausgegeben, anstatt einen (harten) Fehler zu erzeugen. Nachrichten gehen in diesem Fall nicht verloren, da der Puffer dynamisch vergrößert wird.
Die Kennzeichnung als IN-/OUT-Parameter ist für Relays ebenso relevant wie für In- und Outboxen. Relays in einem asynchron aufzurufenden Package erscheinen je nach Kennzeichnung als IN- bzw. OUT-Parameter auf der linken Seite der Inbox- bzw. Outbox-Sektion. Relays ohne Kennzeichnung können durch den Aufrufer nicht verschaltet werden und erscheinen deshalb nicht in der Anzeige.
Komplementäre Einschränkungen gelten für die Auflistung der Relays des Aufrufer-Package in den Auswahllisten der rechten Spalte. Ist ein Relay als OUT-Parameter gekennzeichnet, darf dessen OUT-Ende nicht durch das Package selber verknüpft werden. Das Relay ist dementsprechend nicht in den Auswahllisten der Inbox-Sektion enthalten. Gleiches gilt für die Kennzeichnung als IN-Parameter, die zum Entfernen des Relays aus den Auswahllisten der Outbox-Sektion führt. Ist ein Relay sowohl als IN- und OUT-Parameter gekennzeichnet, wird es in keiner der Auswahllisten angezeigt. Relays ohne Kennzeichnung sind in allen Auswahllisten enthalten.
Ereignisorientierte Nachrichtenverarbeitung (REACT-Testschritt)¶
In Testfällen mit mehreren nebenläufigen Teststrängen besteht oft die Anforderung, gleichzeitig und wiederholt auf das Eintreffen verschiedener Ereignisse (z. B. Nachrichteneingang aus verschiedenen parallelen Packages) zu warten. Außerdem sollen in Abhängigkeit der Art des eintreffenden Ereignisses spezifische Testschritte ausgeführt werden. Diesem Zweck dient der REACT-Testschritt. Er befreit den Testfallersteller von der Notwendigkeit, in einer Schleife sequentiell alle gewünschten Ereignissquellen abzufragen und gestattet eine sehr kompakte Darstellung der pro Ereignis auszuführenden Testschritte. Der REACT-Testschritt ist in der Kategorie Kontrollfluss des Tabs Testschritte zu finden.
Der Bearbeiten-Dialog zeigt die Liste der Ereignisse bzw. Bedingungen, auf die der REACT-Testschritt wartet. Die Liste ist initial leer. Mit dem Hinzufügen-Button können neue Ereignisse definiert werden. Dabei hat der Anwender die Möglichkeit auf
den Nachrichten-Eingang in eine Inbox (Inbox-Condition),
das Eintreffen eines Rückgabewertes eines asynchron aufgerufenen Packages (Future-Condition) oder
den Ablauf einer Zeitspanne (After-Condition)
zu warten.
Je nach gewählter Bedingung muss in der zweiten Spalte
der Name der betreffenden Inbox,
der Name der Zielvariablen für den Package-Rückgabewert,
oder eine Python-Ausdruck für die zu wartenden Zeitspanne
angegeben werden.
Über die Nach-oben- / Nach-unten-Buttons lässt sich die Reihenfolge festlegen, in der die Ereignisquellen abgefragt werden. Die Bearbeitung eingetroffener Ereignisse geschieht sequentiell, d. h. Während der Abarbeitung eines Ereignisses können keine anderen Ereignisse bearbeitet werden. Diese werden aber für die spätere Bearbeitung gespeichert.
Für jedes im REACT-Dialog definierte Ereignis wird im Testfall ein entsprechend gekennzeichneter Container-Testschritt unterhalb des REACT-Testschritts angelegt. In diesen Container-Testschritt können beliebige Testschritte eingefügt werden, die bei Eintreffen des zugehörigen Ereignisses ausgeführt werden sollen.
Zum Beenden der Ereignisbearbeitung und Verlassen des REACT-Testschritts dient der BREAK-Testschritt. Dieser kann in die Ereignisbehandlungs-Teststränge eingefügt werden. Ohne BREAK (oder RETURN) endet der REACT-Testschritt und damit das umgebende Package nie. Der BREAK-Testschritt ist ebenfalls in der Kategorie Kontrollfuss auf dem Tab Testschritte zu finden.