21
Durchführung von Lasttests über das GUI
21.1
Hintergrund und Vergleich mit anderen Techniken

Neben funktionalen und Systemtests eignet sich QF-Test auch zur Durchführung von Lasttests von geringer bis mittlerer Größe, Stresstests oder Performance-Tests. Dabei wird die Performance einer Server Anwendung getestet, indem eine Anzahl von Clients gleichzeitig ausgeführt wird.

Es gibt verschiedene Möglichkeiten, Lasttests durchzuführen. Die meisten davon arbeiten nicht mit echten Clients, sondern setzen direkt auf der Protokollschicht zwischen Client und Server auf, z.B. indem sie HTTP Anfragen absetzen oder mittels RMI oder anderer Middleware Methoden im Server aufrufen.

Protokoll-basierte und GUI-basierte Lasttests haben verschiedene Vor- und Nachteile:

Zusammenfassend lässt sich sagen, dass GUI-basierte Lasttests sehr nützlich und effizient sein können (insbesondere wenn sich funktionale Tests wiederverwenden lassen), vorausgesetzt, die Zahl der zu simulierenden Clients ist nicht zu hoch oder es steht ausreichend Hardware zur Verfügung.

21.2
Lasttest mit QF-Test

QF-Test ist wohl einzigartig in seiner Fähigkeit, mehrere SUT Clients gleichzeitig auf einem Desktop zu treiben, ohne dass diese sich gegenseitig behindern. Zu diesem Zweck filtert QF-Test harte Events, die vom Betriebssystem kommen und verhindert, dass diese das SUT zu einer ungünstigen Zeit erreichen, z.B. während Popup Menüs dargestellt werden oder eine Komponente den Tastaturfokus nicht verlieren darf. Ohne diese Funktionalität würden Interaktionen zwischen SUT Clients auf dem selben Desktop jeden Test schnell zum Scheitern bringen.

21.2.1
Ausführung von Tests in parallelen Threads

Um nicht noch zusätzliche Last auf der Client Seite durch mehrere Instanzen von QF-Test erzeugen zu müssen, kann QF-Test im Batch Modus mittels des Kommandozeilenarguments -threads <Anzahl> mit mehreren parallelen Threads gestartet werden. Jeder dieser Threads führt die selbe Testsuite aus. Pro Thread wird eine Runtime Lizenz benötigt. Stehen nicht genug Runtime Lizenzen zur Verfügung, nutzt QF-Test stattdessen volle Entwicklerlizenzen, es sei denn, dies wird mittels des Kommandozeilenarguments -runtime unterbunden. Weitere Informationen zu Runtime Lizenzen finden Sie in Abschnitt 32.2 beim Kommandozeilenargument -runtime.

Alle Threads sind voneinander unabhängig und starten und steuern ihre eigenen SUT Clients. Zu diesem Zweck hängt QF-Test automatisch an das 'Client' Attribut von jedem Knoten, der einen SUT Client anspricht, einen Identifikator für den aktuellen Thread an. Daher ist es nicht möglich, aus einem Thread das SUT eines anderen Threads anzusprechen.

Zwei Variablen haben bei der Ausführung mit mehreren Threads eine besondere Bedeutung: ${qftest:threads} liefert die Zahl der Threads, die mittels -threads <Anzahl> angegeben wurde (Standard ist 1 bei normaler Ausführung ohne parallele Threads). ${qftest:thread} ist der Index des aktuellen Threads (Standard ist 0).

Die Ausführung mehrerer Clients auf einem Desktop kann zu längeren Verzögerungen als normal führen, vor allem während des Starts der SUTs. Daher sollten Timeouts großzügig erhöht werden, insbesondere für 'Warten auf Client' und 'Warten auf Komponente' Knoten. Außerdem sollten Sie die Optionen unter Wiedergabe->Timeouts (siehe Abschnitt 29.3.5) auf mindestens das Doppelte des Standardwerts erhöhen. Am besten trennen Sie die Optionen für Lasttests von den Optionen für andere Tests, indem Sie mittels des Kommandozeilenarguments -systemcfg <Datei> eine eigene Konfigurationsdatei angeben.

21.2.2
Synchronisierung

Um reproduzierbare Ergebnisse zu erhalten, kann es nötig sein, die Tests in den verschiedenen Threads zu koordinieren, entweder um alle Clients möglichst gleichzeitig den Server ansprechen zu lassen, oder um genau das zu verhindern.

Threads können mit Hilfe eines 'Server Skript' Knotens mit folgendem Skript synchronisiert werden:

rc.syncThreads("identifier", timeout)

Der identifier ist ein Name für den Synchronisationspunkt und timeout ist die maximale Zeit in Millisekunden, nach der alle Threads diesen Synchronisationspunkt erreicht haben müssen. Falls die Threads verschiedene Pfade der Testsuite abarbeiten, so dass nicht alle Threads einen bestimmten Synchronisationspunkt erreichen, können sie die Zahl der zu erwartenden Threads explizit über den Parameter count angeben:

rc.syncThreads("case1", 120000, count=3)

Wird das Timeout überschritten, ohne dass die gewünschte Zahl der Threads den Synchronisationspunkt erreicht, wird eine TestException geworfen. Um stattdessen nur einen Fehler auszugeben und den Test fortzusetzen, kann dem Parameter throw der Wert 0 mitgegeben werden (Standard ist 1):

rc.syncThreads("case1", 120000, count=3, throw=0)
21.2.3
Koordinieren von Tests auf mehreren Rechnern

Wird mehr als ein Rechner benötigt um die gewünschte Anzahl von Clients anzusteuern, können Tests auf mehrere Rechner verteilt werden. Jede QF-Test Instanz auf jedem Rechner kann ihrerseits mehrere parallele Threads ausführen, sofern genügend Lizenzen für die Gesamtzahl der Threads vorhanden sind.

Im Moment bietet QF-Test keine besondere Unterstützung für den koordinierten Start der QF-Test Instanzen auf verschiedenen Rechnern. Dies muss manuell, mit Hilfe eines Skripts, oder mit anderen Tools bewerkstelligt werden. Die Synchronisierung der Tests über verschiedene Rechner hinweg wird aber sehr wohl unterstützt. Hierzu hat die syncThreads Methode einen weiteren optionalen Parameter namens remote. Dieser gibt die Zahl der QF-Test Instanzen an, deren Threads den jeweiligen Synchronisationspunkt erreichen müssen (Standard ist 0, d.h. keine Verteilte Synchronisierung). Jede Instanz synchronisiert dabei zunächst ihre eigenen Threads und synchronisiert sich anschließend mit den anderen QF-Test Instanzen. Erst wenn alle Threads in allen Instanzen den Synchronisationspunkt erreicht haben, wird der Test fortgesetzt.

Um zum Beispiel alle Threads in Tests auf vier Rechnern nach dem Start der SUTs zu synchronisieren, fügen Sie einen 'Server Skript' Knoten am Ende den primären Vorbereitungssequenz mit folgendem Skript ein:

rc.syncThreads("startup", 300000, remote=4)

Sie sollten allerdings die Zahl der Rechner für den remote Parameter nicht hart verdrahten, sondern dafür eine Variable auf Testsuite Ebene mit dem Wert 0 definieren, so dass die Tests auf einem einzelnen Rechner problemlos laufen. Beim Test auf mehreren Rechnern können Sie diese Variable dann entsprechend auf der Kommandozeile überschreiben (siehe Kapitel 8).