Variablen

Video Video: 'Variablen'

Variablen sind von zentraler Bedeutung, wenn es darum geht, die Wiederverwendbarkeit einer Testsuite zu steigern. Zum Einsatz kommen sie vor allem beim Aufruf von 'Prozeduren'. Variablen sind aber auch in vielen anderen Situationen hilfreich.

Variablen können in fast allen Attributen verwendet werden, mit Ausnahme von Wahrheitswerten (Checkboxen). Es gibt drei Varianten von Variablenreferenzen:

  • $(Variablenname) wird zu dem Wert einer vorher definierten Variablen expandiert.
  • ${Gruppe:Name} greift auf Externe Daten aus einem ResourceBundle oder einer Properties Datei zu. Die Gruppen system und qftest sind immer definiert und haben besondere Bedeutungen (vgl. Abschnitt 6.6).
  • $[Ausdruck] führt eine Berechnung durch.

Ermittlung des Wertes einer Variablen

Um zu erklären, wie und warum Variablen an verschiedenen Stellen definiert werden, müssen wir zunächst darauf eingehen, wie der Wert einer Variablen ermittelt wird, wenn diese bei einem Testlauf referenziert wird.

Ein Satz von Variablendefinitionen, genannt Zuordnungen, wird auf einem von zwei Stapeln abgelegt. Der primäre Stapel ist für tatsächliche bzw. direkte Zuordnungen bestimmt, während der sekundäre Stapel Definitionen von Rückfallwerten aufnimmt. Wenn der Wert einer Variable mittels $(...) angefordert wird, durchsucht QF-Test zunächst den primären Stapel von oben nach unten nach einer passenden Definition. Wird keine solche gefunden, wird die Suche im sekundären Stapel fortgesetzt, ebenfalls von oben nach unten. Bleibt auch diese Suche erfolglos, wird eine UnboundVariableException geworfen, sofern Sie nicht mittels der speziellen Syntax ${default:varname:defaultvalue} einen Defaultwert angegeben haben (vgl. Abschnitt 6.6).

Oberste Definitionen
(höchste Bindungskraft)
...
Unterste Definitionen
(niedrigste Bindungskraft)
Oberste Definitionen
(höchste Bindungskraft)
...
Unterste Definitionen
(niedrigste Bindungskraft)
Primärstapel
(direkte Zuordnungen)
Sekundärstapel
(Defaultwerte)
Abbildung 6.1:  Direkte Zuordnungen und Defaultwerte

Dieser Mechanismus unterstützt rekursive bzw. selbstbezogene Variablendefinitionen. Zum Beispiel bewirkt das Setzen der Variable classpath auf den Wert irgendein/pfad/archiv.jar:$(classpath) eine Erweiterung des Wertes einer Definition von classpath mit geringerer Bindungskraft. Existiert keine solche Definition, wird eine RecursiveVariableException ausgelöst.

Definition von Variablen

Variablen können an verschiedenen Stellen definiert werden. Die Definition erfolgt über zweispaltige Tabellen (vgl. Abschnitt 2.2.5). Dort kann in jeder Zeile eine Variable mit Name und Wert angegeben werden.

System Variablen
Abbildung 6.2:  System Variablen

Vier Sätze von Variablendefinitionen sind über die globalen Optionen zugänglich:

Systemspezifische Variablen
Hier können Pfadnamen, JDK oder Betriebssystem-spezifische Werte etc. festgelegt werden. Dieser Satz von Definitionen befindet sich immer ganz unten im sekundären Stapel und hat damit die geringste Bindungskraft. Die Variablen werden zusammen mit anderen Systemoptionen in der System-Konfigurationsdatei gespeichert (vgl. Abschnitt 1.6).
Variablen der aktuellen Suite
Variablen, die sich auf die aktuelle Testsuite beziehen, werden mit dieser abgespeichert. Beim Start eines Tests werden die Variablendefinitionen seiner Suite ganz unten im primären Stapel abgelegt. Wird während des Testlaufs eine Prozedur oder eine Komponente in einer anderen Suite referenziert, werden die Variablen dieser Suite vorübergehend oben auf den sekundären Stapel gelegt.
Variablen von der Kommandozeile
Beim Start von QF-Test können Variablen mit dem Argument -variable <Name>=<Wert> definiert werden. Diese Variablen werden oberhalb der Suite-Variablen auf dem primären Stapel abgelegt. Damit haben Variablen von der Kommandozeile stärkere Bindungskraft als die System oder Suite-Variablen. Zum Beispiel kann ein Variable count = 1 für die Testsuite definiert und $(count) als 'Anzahl Wiederholungen' einer 'Schleife' für schnelle Testläufe benutzt werden. Dann können Sie qftest -batch -variable count=100 ... zum tatsächlichen Testen verwenden. Die Kommandozeilenzuordnungen sind hauptsächlich zur Ihrer Information zugänglich, aber man kann sie auch testhalber verändern.
Globale Variablen
Ebenfalls auf dem primären Stapel, direkt oberhalb der Kommandozeilen-Variablen, befinden sich die globalen Variablen. Diese dienen dazu, Werte zwischen voneinander unabhängigen Teilen der Suite auszutauschen. Hier landen zum Beispiel die Werte, die mittels 'Text auslesen' oder 'Index auslesen' Knoten vom SUT ausgelesen werden, oder Definitionen mit Hilfe eines 'Variable setzen' Knotens. Bei der interaktiven Arbeit löscht QF-Test die globalen Variablen nicht, wenn ein Test gestartet wird und macht diese sogar in den Optionen zugänglich. Sie sollten aber im Hinterkopf behalten, dass diese Variablen zunächst durch den Ablauf des Tests definiert werden müssen, bevor sie referenziert werden. Daher sollten Sie vor einem echten Testlauf die globalen Variablen mittels »Wiedergabe«-»Globale Variablen löschen« löschen. Läuft QF-Test im Batchmodus (vgl. Abschnitt 1.7), werden die globalen Variablen vor der Ausführung jedes mit dem Kommandozeilenargument -test <Index>|<ID> angegebenen Tests gelöscht.

Alle weiteren Definitionen sind Teil der Testsuite selbst:

  • Die 'Variablendefinitionen' von Sequenz-Knoten werden auf den primären Stapel gelegt, wenn der Testlauf diese Sequenz betritt und beim Verlassen derselben wieder entfernt.
  • Beim Aufruf einer 'Prozedur' durch einen 'Prozeduraufruf' werden die 'Variablendefinitionen' des Aufrufs auf den primären Stapel gelegt. Die 'Variablendefinitionen' der 'Prozedur' dienen dagegen als Rückfallwerte und landen auf dem sekundären Stapel. Ist die 'Prozedur' beendet, werden beide Sätze wieder entfernt.

Variablen Beispiel

Betrachten wir folgendes Beispiel:

Variablen Beispiel
Abbildung 6.3:  Variablen Beispiel

Die 'Sequenz' "Login" enthält einen 'Prozeduraufruf' der 'Prozedur' "login" die zwei Parameter erwartet, user und password. Die Defaultwerte der 'Prozedur' sind user=username und password=pwd. Der 'Prozeduraufruf' überschreibt diese mit user=myname und password=mypassword.

Die "login" 'Prozedur' enthält selbst 'Prozeduraufrufe' von weiteren 'Prozeduren' in einer anderen Testsuite namens "lib.qft", um Name und Passwort in GUI-Komponenten des SUT zu schreiben. Nehmen wir an, dass die 'Prozeduren' dieser Bibliothek viele gemeinsame Parameter haben. Anstatt für jede 'Prozedur' die gleichen Defaultwerte festzulegen, werden diese in den Variablen der Testsuite abgelegt. Das ist praktisch bei der Erstellung und Bearbeitung der 'Prozeduren' der Bibliothek, da diese damit einzeln ausgeführt werden können, ohne dass extra 'Prozeduraufrufe' erstellt werden müssen.

Das folgende Diagramm zeigt den Zustand des primären und des sekundären Stapels während der Ausführung der 'Prozedur' "lib.qft#setUser":

'Prozeduraufruf' "lib.qft#setUser"
'Prozeduraufruf' "login"
user=myname
password=mypassword
'Sequenz' "Login"
Globale Variablen
Variablen von der Kommandozeile
Suite Variablen
'Prozedur' "lib.qft#setUser"
Testsuite "lib.qft"
user=libuser
password=libpwd
'Prozedur' "Login"
user=user
password=pwd
System Variablen
Primärstapel
(direkte Zuordnungen)
Sekundärstapel
(Defaultwerte)
Abbildung 6.4:  Beispiel zu Variablenbindungen

Besonders hervorzuheben ist hier, dass der 'Prozeduraufruf' von "lib.qft#setUser" in der 'Prozedur' "login" den Parameter user nicht noch einmal definieren muss, er wird sozusagen "durchgereicht". Grundsätzlich sollten Sie beim Aufruf einer 'Prozedur' aus einer anderen 'Prozedur' heraus einen Parameter genau dann und nur dann definieren, wenn er noch nicht explizit definiert wurde oder wenn Sie einen anderen Wert verwenden wollen.

Daten aus der GUI auslesen

Oft ist es notwendig einen Wert aus der Oberfläche des SUT auszulesen, um diese als Eingabe für den Test zu verwenden.

QF-Test bietet für diese Aufgabe einen speziellen Satz von Abfrageknoten, verfügbar unter »Einfügen«-»Verschieden Knoten«:

Die ermittelten Werte werden lokalen oder globalen Variablen zugewiesen, die im Abfragekonten deklariert werden können.

Anstatt einen Abfrageknoten per Hand einzufügen, kann ein solcher leichter erzeugt werden, indem man erst einen Mausklick-Knoten auf die gewünschte Komponente aufzeichnet und diesen dann mit Hilfe der Konvertierungsoperation in den gewünschten Abfrageknoten umwandelt.

JSON-Daten

Bei der Arbeit mit HTTP Requests oder dem WebApi werden die Daten oft als JSON-Objekt bereitgestellt. Wenn Sie das Objekt serialisieren, also in eine JSON-Zeichenkette umwandeln und einer QF-Test Variablen zuweisen wollen, können Sie die Methoden rc.setLocalJson() und rc.setGlobalJson() von Die API des Runcontexts in einem Skript-Knoten verwenden.

Wenn Sie eine JSON-Zeichenkette in ein JSON-Objekt umwandeln wollen, steht Ihnen in einem Skript-Knoten rc.getJson() im Die API des Runcontexts zur Verfügung.

JSON-Objekte können mit den im Das JSON Modul bereitgestellten Methoden bearbeitet werden.

Externe Daten und spezielle Gruppen

Auf externe Daten kann mit Hilfe von 'Ressourcen laden' und 'Properties laden' Knoten zugegriffen werden. Diese weisen einem Satz von Definitionen einen Gruppennamen zu. Den Wert einer Ressource oder Property mit der Bezeichnung Name erhalten Sie mit der Syntax ${Gruppe:Name}.

Wird ein Test im Batchmodus ausgeführt (vgl. Abschnitt 1.7), löscht QF-Test die Ressourcen und Properties vor der Ausführung jedes mit dem Kommandozeilenargument -test <Index>|<ID> angegebenen Tests. Im interaktiven Modus werden diese aufgehoben, um das Erstellen einer Testsuite zu vereinfachen. Vor einem kompletten Testlauf sollten Sie allerdings mittels »Wiedergabe«-»Ressourcen und Properties löschen« für eine saubere Ausgangsbasis sorgen.

Zusätzlich zu ResourceBundles und Properties sind einige spezielle Gruppen definiert, die immer vorhanden sind:

system
Über die Gruppe system haben Sie Zugriff auf die System Properties der laufenden Java-VM (für Programmierer: System.getProperties()). Es handelt sich dabei immer um die VM, mit der QF-Test gestartet wurde, da die Variablen-Expansion dort stattfindet.
So liefert etwa ${system:java.class.path} den Klassenpfad, mit dem QF-Test gestartet wurde oder ${system:user.home} das Heimatverzeichnis des Benutzers. Welche Namen in der system Gruppe definiert sind, hängt vom verwendeten JDK ab.
env
Falls das Betriebssystem Umgebungsvariablen wie PATH, TMP oder JAVA_HOME unterstützt (was auf praktisch allen Systemen der Fall ist, auf denen QF-Test läuft), kann über die Gruppe env auf diese Variablen zugegriffen werden.
default
3.4+ Sie können über die Gruppe default einen Defaultwert für eine Variable angeben. Die Syntax hierfür ist ${default:varname:defaultvalue}. Dies ist sehr nützlich für Dinge wie generische Komponenten und nahezu überall, wo es einen sinnvollen Defaultwert für eine Variable gibt, da der Defaultwert dann eng mit der Anwendung der Variablen verbunden ist und nicht auf 'Sequenz' oder Testsuite-Ebene definiert werden muss. Natürlich sollten Sie diese Syntax nur verwenden, wenn die Variable nur an einer oder sehr wenigen Stellen benutzt wird. Wenn Sie dieselbe Variable mit dem selben Defaultwert an verschiedenen Stellen verwenden, ist es besser, die normale $(...) Syntax zu verwenden und den Defaultwert explizit festzulegen, da dieser dann bei Bedarf an einer einzigen Stelle geändert werden kann.
id
3.1+ Die Gruppe id dient dazu, QF-Test IDs von Komponenten zu referenzieren. Die Werte in dieser Gruppe expandieren einfach zu sich selbst, d.h. "${id:wasauchimmer}" wird zu "wasauchimmer". Man kann QF-Test IDs von Komponenten zwar auch ohne diese Gruppe ansprechen, allerdings verbessert die Referenzierung über diese Gruppe die Lesbarkeit der Tests. Vor allem aber werden diese QF-Test IDs auch beim Verschieben der referenzierten Komponente oder Änderungen an ihrer QF-Test ID angepasst.
idlocal
4.2.3+ Die Gruppe idlocal ist analog zur Gruppe id, enthält aber zusätzlich den Pfad der aktuellen Testsuite, d.h. aus "${idlocal:x}" wird "pfad/zur/aktuellen/suite/suite.qft#x". Damit lässt sich erzwingen, dass eine Komponente nur aus der Testsuite genommen wird, die zum Zeitpunkt der Expansion aktuell ist, selbst wenn es eine Komponente mit derselben 'QF-Test ID' in der Zieltestsuite für den Prozeduraufruf gibt.
quoteitem
4.0+ Mit Hilfe der Gruppe quoteitem können Sie bequem Sonderzeichen wie '@', '&' und '%' im textuellen Index eines Unterelements schützen, um zu verhindern, dass dieses als mehrere Unterelemente interpretiert wird. Aus "${quoteitem:user@host.org}" wird zum Beispiel "user\@host.org".
quoteregex, quoteregexp
4.0+ Die Gruppe quoteregex mit ihrem Alias quoteregexp kann zum Schützen von Sonderzeichen mit spezieller Bedeutung in regulären Ausdrücken verwendet werden. Dies ist hilfreich, wenn reguläre Ausdrücke dynamisch zusammengebaut werden.
quotesmartid
6.0.1+ Die Gruppe quotesmartid schützt analog zu quoteitem die Zeichen für Unterelemente '@', '&' und '%', außerdem die Zeichen ':', '=', '<' und '>' mit spezieller Bedeutung für SmartIDs. Aus "${quotesmartid:Name: A & B}" wird zum Beispiel "Name\: A \& B".
qftest
Die Gruppe namens qftest stellt verschiedene Werte zur Verfügung, die beim Ablauf eines Tests von Bedeutung sein können. Die bisher definierten Werte können Sie den folgenden Tabellen entnehmen.
NameBedeutung
32 oder 32bit Nicht mehr relevant, da die Unterstützung von 32 Bit Java für QF-Test mit Version 8.0 eingestellt wurde.
true wenn QF-Test in einer 32-Bit-Java-VM läuft - was nicht bedeutet, dass dies auf einem 32 Bit Betriebssystem erfolgt - andernfalls false.
64 oder 64bit Nicht mehr relevant, da die Unterstützung von 32 Bit Java für QF-Test mit Version 8.0 eingestellt wurde.
true wenn QF-Test in einer 64 Bit Java-VM läuft, andernfalls false.
batchtrue falls QF-Test im Batch Modus läuft, false im interaktiven Modus.
client.baseEngineName.<name> Der Basisname der primären Engine des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. fx.
client.browser.<name> Der Name bzw. Typ des Browsers des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. safari. Steht nur für Web-Clients zur Verfügung.
client.deviceName.<name> Ein Name für das (emulierte) Gerät des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. Pixel_3. Steht nur zur Verfügung für Android-Clients nach der Instrumentierung und entspricht dort bei emulierten Geräten dem AVD-Namen.
client.deviceType.<name> Der Typ des (emulierten) Geräts des Clients, der mit <name> als 'Client' Attribut gestartet wurde. Kann die Werte emulator (für ein emuliertes Gerät) und device (für ein real angeschlossenes Gerät) annehmen. Steht nur zur Verfügung für Android-Clients nach der Instrumentierung.
client.connectionMode.<name> Der Name des Verbindungsmodus des Clients, der mit <name> als 'Client' Attribut gestartet wurde. Gültige Werte sind qfdriver, cdpdriver, webdriver und embedded. Steht nur für Web-Clients zur Verfügung.
client.engine.<name> Die primäre Engine des Clients, der mit <name> als 'Client' Attribut gestartet wurde. Das Ergebnis besteht dabei aus dem Basisnamen der Engine und einem numerischen Index, z.B. fx0.
client.engineNames.<name> Eine Liste aller verbundenen Engines des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. [fx0, web_fx0].
client.exitCode.<name> Der Rückgabewert des letzten Prozesses, der mit <name> als 'Client' Attribut gestartet wurde. Ist der Prozess noch aktiv, ist das Ergebnis leer.
client.mainVersion.<name> Der Hauptversion des Browsers bzw. des Geräte-Betriebssystems des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. 121. Steht nur zur Verfügung für Web-Clients, nachdem das erste Browserfenster geöffnet wurde, und für Android-Clients nach der Instrumentierung.
client.output.<name> Die Ausgaben des letzten Prozesses, der mit <name> als 'Client' Attribut gestartet wurde. Das Maximum an gespeichertem Text wird durch die Option Maximalgröße des Terminals für einen Client (kB) bestimmt.
client.SDKVersion.<name> Der SDK-Version des Geräte-Betriebssystems des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. 29. Steht nur zur Verfügung für Android-Clients nach der Instrumentierung.
client.stdOut.<name> Die vom letzten Prozesses, der mit <name> als 'Client' Attribut gestartet wurde, auf den Standardausgabestream (stdout) geschriebenen Ausgaben. Das Maximum an gespeichertem Text wird durch die Option Maximalgröße des Terminals für einen Client (kB) bestimmt.
client.stdErr.<name> Die vom letzten Prozesses, der mit <name> als 'Client' Attribut gestartet wurde, auf den Fehlerausgabestream (stderr) geschriebenen Ausgaben. Das Maximum an gespeichertem Text wird durch die Option Maximalgröße des Terminals für einen Client (kB) bestimmt.
client.version.<name> Der Browserversion bzw. die Version des Geräte-Betriebssystems des Clients, der mit <name> als 'Client' Attribut gestartet wurde, z.B. 121.10.2967.10. Steht nur zur Verfügung für Web-Clients, nachdem das erste Browserfenster geöffnet wurde, und für Android-Clients nach der Instrumentierung.
clients Eine Liste der Namen der aktiven Client-Prozesse, mit Zeilentrennern getrennt.
clients.all Eine Liste der Namen aller Client-Prozesse, mit Zeilentrennern getrennt. Die Liste enthält aktive Prozesse ebenso wie kürzlich beendete, analog zum "Clients" Menü.
count.exceptions Anzahl der Exceptions im aktuellen Testlauf.
count.errors Anzahl der Fehler im aktuellen Testlauf.
count.warnings Anzahl der Warnungen im aktuellen Testlauf.
count.testCases Gesamtanzahl der Testfälle (ausgeführt und übersprungen) im aktuellen Testlauf.
count.testCases.exception Anzahl der Testfälle mit Exceptions im aktuellen Testlauf.
count.testCases.error Anzahl der Testfälle mit Fehlern im aktuellen Testlauf.
count.testCases.expectedToFail Anzahl der erwartet fehlgeschlagenen Testfälle im aktuellen Testlauf.
count.testCases.ok Anzahl der erfolgreichen Testfälle im aktuellen Testlauf.
count.testCases.ok.percentage Prozentsatz der erfolgreichen Testfälle im aktuellen Testlauf.
count.testCases.skipped Anzahl der übersprungenen Testfälle im aktuellen Testlauf.
count.testcases.notImplemented Anzahl der nicht implementierten Testfälle im aktuellen Testlauf.
count.testCases.run Anzahl der ausgeführten Testfälle im aktuellen Testlauf.
count.testSets.skipped Anzahl der übersprungenen Testfallsätze im aktuellen Testlauf.
dir.cacheDas Cache-Verzeichnis von QF-Test
dir.groovyVerzeichnis von Groovy
dir.javascriptVerzeichnis von JavaScript
dir.jythonVerzeichnis von Jython
dir.logDas Logverzeichnis von QF-Test
dir.pluginDas Pluginverzeichnis von QF-Test
dir.rootWurzelverzeichnis von QF-Test
dir.runlogProtokollverzeichnis von QF-Test
dir.systemDas systemspezifische Konfigurationsverzeichnis von QF-Test.
dir.userDas anwenderspezifische Konfigurationsverzeichnis von QF-Test
dir.versionVersionsspezifisches Verzeichnis von QF-Test
engine.<componentId>Ermittelt die GUI-Engine, die für die angegebene Komponente zuständig ist (vgl. Kapitel 44).
languageDie Sprache in welcher QF-Test seine graphische Oberfläche darstellt.
licenseDer Pfad der Lizenzdatei
systemCfgDer Pfad der Systemkonfigurationsdatei
userCfgDer Pfad der benutzerspezifischen Konfigurationsdatei
executable Die ausführbare qftest Programmdatei passend zur aktuell laufenden QF-Test Version, inklusive vollem Pfad zu deren bin Verzeichnis und mit .exe Anhang unter Windows. Dies ist hilfreich, falls Sie QF-Test aus QF-Test starten wollen, z.B. um einen Daemon-Aufruf auszuführen oder Reports zu generieren.
isInRerun"true", wenn aktuelle Ausführung nochmals ausgeführt wird, sonst "false", Details siehe Abschnitt 24.3.2.
isInRerunFromLog"true", wenn Testlauf aus dem Protokoll nochmals gestartet wurde, sonst "false", Details siehe Abschnitt 24.3.1.
javaStandard Java-Programm (javaw unter Windows, java unter Linux) oder das explizit mittels -java <Programm>(abgekündigt) angegebene Java-Programm.
java.mainVersion Die Hauptversion des JRE mit dem QF-Test aktuell läuft, wobei 8 für Java 1.8 genommen wird, also z.B. 8, 11 oder 17.
java.subVersion Die Unterversion des JRE mit dem QF-Test aktuell läuft. Für Java 8 wird die Unterversion nach dem '_ genommen, was z.B. für java.version 1.8.0_302 zu 302 führt. Für Java 9 oder höher ist dies die normale Unterversion, also z.B. 9 in Fall von java.version 11.0.9.
linux"true" unter Linux, andernfalls "false"
macOS"true" unter macOS, andernfalls "false"
os.fullVersionDie vollständige Version des Betriebssystems
os.mainVersionDie Hauptversion des Betriebssystems, z.B. "10" für Windows 10
os.nameDer Name des Betriebssystems
os.versionDie konkrete Version des Betriebssystems. Unter Windows kann diese ggf. nicht vollständig sein. In diesem Fall sollten Sie auf os.fullversion zurückgreifen.
project.dirDas Verzeichnis des aktuellen Projektes. Die Variable ist nicht definiert, wenn die aktuelle Test suite sich nicht in einem Projekt befindet.
rerunCounterNummer des aktuellen Versuchs der Neuausführung, sonst immer 0, Details siehe Abschnitt 24.3.2.
return Der letzte mittels eines 'Return' Knotens aus einer 'Prozedur' zurückgegebene Wert.
runID Die Run-ID des aktuellen Testlaufs. Nähere Informationen zur Run-ID finden Sie in Abschnitt 23.1.
screen.heightBildschirmhöhe in Pixel
screen.widthBildschirmbreite in Pixel
skipNode Dieser spezielle Wert ist nur für erfahrene Anwender. Er weist QF-Test an, die Ausführung des aktuellen Knotens zu überspringen. Sein primärer Nutzen ist als Wert für eine Variable im Attribut 'Text' eines 'Texteingabe' Knotens, dessen Attribute 'Zielkomponente zunächst leeren' gesetzt ist. Ein leerer Wert würde hier zu einem Löschen des Textfeldes führen, $_{qftest:skipnode} hingegen das Feld unverändert lassen. Weiterhin kann skipnode für besondere Fälle der Ablaufsteuerung eingesetzt werden, indem z.B. eine Variable im Kommentar eines Knotens definiert und ihr selektiv der Wert $_{qftest:skipnode} übergeben wird. Beachten Sie bitte, dass hierfür praktisch immer die Lazy Binding Syntax '$_' verwendet werden sollte, da ansonsten die Expansion im Parameter eines 'Prozeduraufruf' Knotens zum Überspringen des gesamten Aufrufs führen würde.
suite.dirVerzeichnis der aktuellen Suite
suite.fileDateiname der aktuellen Suite ohne Verzeichnis
suite.pathDateiname der aktuellen Suite mit Verzeichnis
suite.nameDer Name der aktuellen Testsuite.
testCase.name Der Name des aktuellen 'Testfalls', leer falls im Moment kein 'Testfall' ausgeführt wird.
testCase.id Die QF-Test ID des aktuellen 'Testfalls', leer falls im Moment kein 'Testfall' ausgeführt wird.
testCase.qName Der qualifizierte Name des aktuellen 'Testfalls', inklusive der Namen seiner 'Testfallsatz' Parentknoten. Leer falls im Moment kein 'Testfall' ausgeführt wird.
testCase.reportName Der expandierte Report-Name des aktuellen 'Testfalls', leer falls im Moment kein 'Testfall' ausgeführt wird.
testCase.splitLogName Der qualifizierte Name des aktuellen 'Testfalls' als Dateiname, inklusive der Namen seiner 'Testfallsatz' Parentknoten als Verzeichnisse. Leer falls im Moment kein 'Testfall' ausgeführt wird.
testSet.name Der Name des aktuellen 'Testfallsatzes', leer falls im Moment kein 'Testfallsatz' ausgeführt wird.
testSet.id Die QF-Test ID des aktuellen 'Testfallsatzes', leer falls im Moment kein 'Testfallsatz' ausgeführt wird.
testSet.qName Der qualifizierte Name des aktuellen 'Testfallsatzes', inklusive der Namen seiner 'Testfallsatz' Parentknoten. Leer falls im Moment kein 'Testfallsatz' ausgeführt wird.
testSet.reportName Der expandierte Report-Name des aktuellen 'Testfallsatzes', leer falls im Moment kein 'Testfallsatz' ausgeführt wird.
testSet.splitLogName Der qualifizierte Name des aktuellen 'Testfallsatzes' als Dateiname, inklusive der Namen seiner 'Testfallsatz' Parentknoten als Verzeichnisse. Leer falls im Moment kein 'Testfallsatz' ausgeführt wird.
testStep.name Der Name des aktuellen 'Testschritts' (inkl. @teststep doctag), leer falls im Moment kein 'Testschritt' ausgeführt wird.
testStep.qName Der qualifizierte Reportname des aktuellen 'Testschritts' (inkl. @teststep doctag), inklusive der Reportnamen seiner 'Testschritt' Parentknoten aber ohne 'Testfall' und 'Testfallsatz' Parentknoten. Leer falls im Moment kein 'Testschritt' ausgeführt wird.
testStep.reportName Der expandierte Report-Name des aktuellen 'Testschritts' (inkl. @teststep doctag), leer falls im Moment kein 'Testschritt' ausgeführt wird.
thread Der Index des aktuellen Threads. Immer 0, es sei denn QF-Test wird mit dem Kommandozeilenargument -threads <Anzahl> gestartet.
threads Die Anzahl der parallelen Threads. Immer 1, es sei denn QF-Test wird mit dem Kommandozeilenargument -threads <Anzahl> gestartet.
versionQF-Test Version
version.buildQF-Test Buildnummer
windows"true" unter Windows, andernfalls "false"
Tabelle 6.1:   Definitionen in der Gruppe qftest

Berechnungen

Es kann nötig sein, für den korrekten Ablauf eines Tests kleine Berechnungen durchzuführen. Diese erledigen Sie mit Hilfe der speziellen Variablensyntax $[Ausdruck], die Sie in jedem Attribut, das Variablen unterstützt, verwenden können.

Es werden die Operatoren +, -, *, / und % (Modulo) für ganze und Fließkommazahlen unterstützt. Letztere verwenden den Punkt als Dezimalzeichen, nicht das Komma.

Ausdrücke der Form $[...] bieten aber noch viel weitergehende Möglichkeiten, da sie vom Jython Interpreter ausgewertet werden. Zulässig sind alle Ausdrücke deren Syntax für die Jython Methode eval gültig ist. Näheres zu Jython siehe Kapitel 11.

Hinweis Der Zugriff auf QF-Test Variablen in $[...] Ausdrücken folgt den selben Regeln wie in Jython Skripten (vgl. Abschnitt 11.2.3). Die standard QF-Test Syntax $(...) und ${...:...} kann für numerische und Boolesche Werte verwendet werden. Auf Zeichenketten sollte mittels rc.lookup(...) zugegriffen werden.

3.0+6.8
Immediate und Lazy Binding

Es gibt einen sehr subtilen Aspekt bei der Verwendung von QF-Test Variablen auf den wir noch genauer eingehen müssen:

Wenn ein Satz von Variablendefinitionen auf einen der beiden Stapel gelegt wird gibt es zwei Möglichkeiten zur Behandlung von Referenzen auf Variablen im Wert einer Definition. Hat z.B. die Variable namens 'x' den Wert '$(y)', kann dieser Wert wortwörtlich gespeichert werden, so dass der Wert von '$(y)' erst zu einem späteren Zeitpunkt ermittelt wird, wenn irgendwo '$(x)' referenziert wird. Alternativ kann der Wert von '$(y)' schon beim Binden der Variablen 'x' ermittelt und als Wert von x abgelegt werden. Der erste Ansatz wird als "Lazy Binding" oder "Late Binding" bezeichnet, der zweite als "Immediate Binding".

Der Unterschied zwischen beiden ist natürlich der Zeitpunkt der Expansion und damit der Kontext in dem eine Variable expandiert wird. In den allermeisten Fällen ist das Ergebnis das gleiche, aber es gibt Situationen in denen es von großer Bedeutung ist, Lazy oder Immediate Binding zu verwenden. Betrachten wir die folgenden zwei Beispiele:

Eine Testsuite-Bibliothek stellt eine Prozedur zum Start des SUT mit verschiedenen JDK Versionen bereit. Die Variable 'jdk' wird als Parameter an diese Prozedur übergeben. Zur einfacheren Nutzung definiert der Autor der Bibliothek weitere hilfreiche Variablen auf Testsuite-Ebene, z.B. 'javabin' für das ausführbare Java-Programm mit dem Wert '/opt/java/$(jdk)/bin/java'. Zu dem Zeitpunkt, zu dem 'javabin' in den Testsuite Variablen gebunden wird, könnte 'jdk' noch undefiniert sein, so dass Immediate Binding zu einem Fehler führen würde. Doch selbst wenn 'jdk' mit einem Standardwert belegt ist hat Immediate Binding nicht den gewünschten Effekt, da sich der Wert von 'javabin' durch Übergabe eines anderen Wertes für 'jdk' an die Prozedur nicht mehr ändert. Lazy Binding ist hier also die Methode der Wahl.

Betrachten wir eine andere Bibliothek mit einer Prozedur zum Kopieren einer Datei. Die zwei Parameter namens 'source' und 'dest' legen die Ausgangsdatei und das Zielverzeichnis fest. Der Aufrufer der Prozedur möchte die Datei 'data.csv' aus dem Verzeichnis seiner Testsuite an einen anderen Ort kopieren. Die nahe liegende Idee ist, für den Parameter 'source' den Wert '${qftest:suite.dir}/data.csv' an die Prozedur zu übergeben. Mit Immediate Binding liefert '${qftest:suite.dir}' in der Tat das Verzeichnis der aufrufenden Suite. Wird allerdings Lazy Binding verwendet, findet die Expansion erst innerhalb der Prozedur statt, so dass '${qftest:suite.dir}' das Verzeichnis der Bibliotheks-Suite liefert, was im Allgemeinen nicht den gewünschten Effekt hat.

In QF-Test Versionen bis einschließlich 2.2 wurde ausschließlich Lazy Binding unterstützt. Wie die obigen Beispiele zeigen, sind beide Varianten sinnvoll und notwendig. Da es intuitiver und leichter nachvollziehbar ist, ist Immediate Binding nun der Standard, was mittels der Option Werte von Variablen beim Binden sofort expandieren geändert werden kann. Die Option Lazy Binding verwenden falls sofortiges Expandieren scheitert ergänzt diese und ermöglicht eine einfache Migration von älteren Testsuiten zum Gebrauch von Immediate Binding. Die Warnungen, die in diesem Zusammenhang ausgegeben werden, helfen Ihnen, die wenigen Stellen zu lokalisieren, an denen Sie wie unten beschrieben explizit Lazy Binding verwenden sollten. Bis auf die äußerst seltenen Fälle, in denen Lazy Binding benötigt wird, Immediate Binding aber auch funktioniert, so dass kein Rückgriff auf Lazy Binding gemacht wird, sollten alle Tests ohne Änderungen lauffähig sein.

In den wenigen Fällen, in denen es einen Unterschied macht, ob eine Variable mittels Immediate oder Lazy Binding definiert wird, kann dies unabhängig von der Voreinstellung durch eine alternative Variablen-Syntax erzwungen werden. Für Immediate Binding verwenden Sie '$!' anstatt nur '$', Lazy Binding erhalten Sie mittels '$_'. Um z.B. auf Testsuite-Ebene eine Variable zu definieren, deren Wert eine Datei im Verzeichnis dieser Suite ist, verwenden Sie '$!{qftest:suite.dir}/somefile'. Wenn Sie wie in obigem 'jdk' Beispiel Lazy Binding benötigen, verwenden Sie '$_(jdk)'.

Hinweis Mit Lazy Binding war es egal, in welcher Reihenfolge Variablen oder Parameter in einem Knoten oder Datentreiber definiert waren, da während des Bindens keine Expansion stattfand. Bei Immediate Binding werden Variablen von oben nach unten, bzw. bei Datentreibern von links nach rechts expandiert. Das bedeutet, dass die Definition von x=1 und y=$(x) funktioniert und y den Wert 1 erhält, wenn x zuerst definiert wird. Kommt hingegen die Definition von y zuerst, führt dies zu einem Fehler oder dem oben beschriebenen Rückfall auf Lazy Binding.