'Checks' gehören zu QF-Test's nützlichsten Features. Ohne die Fähigkeit, die
Ergebnisse von simulierten Aktionen zu verifizieren, wäre Testautomatisierung weitgehend
nutzlos. Allerdings beschränkt sich das Repertoire von Checks in QF-Test natürlich auf die
gängigen Attribute der standard Komponenten. Für besondere, selten genutzte Attribute
oder für eigene Komponenten können Sie auf 'SUT Skript' Knoten ausweichen,
dort den benötigten Wert auslesen und über die Methode rc.checkEqual() mit
dem erwarteten Wert vergleichen. So ein 'SUT Skript' Knoten funktioniert
schnell und zuverlässig und lässt sich in einer 'Prozedur' modularisieren. Er
hat aber zwei Nachteile: Er lässt sich nicht aufzeichnen und er ist abschreckend für
Nicht-Entwickler.
Mit Hilfe des in diesem Abschnitt beschriebenen API ist es möglich, die standard Checks
von QF-Test zu erweitern. QF-Test's eigene Checks basieren sogar selbst darauf. Durch
Implementieren und Registrieren eines Checkers für eine Klasse von GUI
Elementen können Sie Ihre eigenen Checks erstellen, die genauso aufgenommen und
wiedergegeben werden können wie die standard Checks.
Um dies so einfach wie möglich zu gestalten kümmert sich QF-Test selbst um alle Details,
von der Darstellung im Check-Popupmenü, Abholen der Checkdaten, Aufnahme des
entsprechenden 'Check' Knotens um die Daten zu speichern, Schicken der Daten an
das SUT zur Wiedergabe, Abholen der dann gültigen Checkdaten bis hin zum Vergleichen der beiden
Werte und Darstellung der Ergebnisse im Protokoll. Alles was Sie dazu beitragen müssen,
ist QF-Test mitzuteilen, welche Checks Ihr Checker implementiert und für diese
auf Anfrage die Checkdaten zu ermitteln.
Illustrative Beispiele finden Sie am Ende des Kapitels sowie in der Testsuite
carconfig_de.qft im Verzeichnis demo/carconfig Ihrer QF-Test
Installation.
Das Interface de.qfs.apps.qftest.extensions.checks.Checker muss
implementiert werden, um eigene Checks für Ihre Anwendung bereitzustellen. Die damit
verbundenen Hilfsklassen und Interfaces werden in den folgenden Abschnitten
beschrieben.
| |
|
|
| |
CheckType[] getSupportedCheckTypes(Object element, Object item) |
| Parameter |
element |
Das GUI Element, für das die möglichen Checks ermittelt werden.
|
item |
Ein optionales Unterelement, das geprüft werden soll. Sein Typ hängt von der Art
des GUI Elements und der dafür registrierten ItemResolver ab, wie in
Abschnitt 39.2.5 beschrieben.
|
| Rückgabewert |
Ein Array mit den CheckType Objekten, die Ihr Checker
unterstützt. Das erste Element ist der Standard für die Check-Aufnahme mit einem
Linksklick. Falls item null ist, liefern Sie nur die Checks zurück,
die sich auf das GUI Element als ganzes beziehen. Ansonsten ist es am besten, alle
verfügbaren Checks mit oder ohne Unterelement zu liefern, da der Anwender zwar
vielleicht auf ein Unterelement geklickt hat, aber trotzdem einen Check für das
ganze GUI Element aufnehmen möchte.
|
| |
CheckData getCheckData(Object element, Object item, CheckType type) |
| Parameter |
element |
Das GUI Element, für das die Checkdaten ermittelt werden sollen.
|
item |
Ein optionales Unterelement, das geprüft werden soll. Sein Typ hängt von der Art
des GUI Elements und der dafür registrierten ItemResolver ab, wie in
Abschnitt 39.2.5 beschrieben.
|
type |
Die Art des auszuführenden Checks.
|
| Rückgabewert |
Die Checkdaten für den aktuellen Zustand des GUI Elements selbst, falls
item null ist, oder des Unterelements. Der gewünschte Checktyp wird
über den Parameter type definiert, der normalerweise einer der vorher
von getSupportedCheckTypes zurückgelieferten Checktypen sein sollte.
Falls Sie den gewünschten Check für das angegebene Ziel nicht ausführen können,
liefern Sie null.
|
| |
Pair getCheckDataAndItem(Object element, Object item, CheckType type) |
| Parameter |
element |
Das GUI Element, für das die Checkdaten ermittelt werden sollen.
|
item |
Ein optionales Unterelement, das geprüft werden soll. Sein Typ hängt von der Art
des GUI Elements und der dafür registrierten ItemResolver ab, wie in
Abschnitt 39.2.5 beschrieben.
|
type |
Die Art des auszuführenden Checks.
|
| Rückgabewert |
Ein Pair bestehend aus den Checkdaten für das GUI Element oder
Unterelement sowie das Unterelement, auf das sich der Check bezieht. Letzeres kann
null sein.
|
| |
|
| |
Die Klasse de.qfs.lib.util.Pair für den Rückgabewert von
getCheckDataAndItem ist eine einfache Hilfsklasse, die praktisch für die
Gruppierung von zwei Objekten ist. Sie müssen nur ihren Konstruktor kennen, können
aber natürlich auch ihre Werte auslesen:
| |
|
|
| |
Pair(Object first, Object second) |
| Parameter |
first | Das erste Objekt. Kann null sein. |
second | Das zweite Objekt Kann null sein. |
| |
Object getFirst() |
| Rückgabewert | Das erste Objekt. |
| |
Object getSecond() |
| Rückgabewert | Das zweite Objekt. |
| |
|
| |
Ein de.qfs.apps.qftest.extensions.checks.CheckType kapselt die Definition
einer spezifischen Art von Check. Er kombiniert einen CheckDataType mit
einer Bezeichnung und stellt eine anwenderfreundliche Repräsentation für das Checkmenü
bereit. Sofern Sie nicht mehrsprachige Darstellungen im Checkmenü benötigen, sollten
Sie dieses Interface nie selbst implementieren, sondern einfach einen
de.qfs.apps.qftest.extensions.checks.DefaultCheckType instanziieren:
| |
|
|
| |
DefaultCheckType(String identifier, CheckDataType dataType, String description) |
| Parameter |
identifier |
Der Bezeichner des Checks. Die standard Checks von QF-Test benutzen hierfür
ausschließlich Kleinbuchstaben. Um Konflikte zu vermeiden, beginnen Sie Ihre
Bezeichner einfach groß.
|
dataType |
Der CheckDataType für Ihre Checkdaten.
|
description |
Die Beschreibung des Checks für das Checkmenü.
|
| |
|
| |
Der Vollständigkeit halber führen wir auch die Methoden des CheckType
Interfaces auf:
| |
|
|
| |
String getIdentifier() |
| Rückgabewert |
Der Bezeichner des Checktyps.
|
| |
CheckDataType getDataType() |
| Rückgabewert |
Der Datentyp des Checks.
|
| |
String getDescription() |
| Rückgabewert |
Die Beschreibung für den Checktyp.
|
| |
|
| |
Die Klasse de.qfs.apps.qftest.extensions.checks.CheckDataType ist
vergleichbar zu Enum. Sie definiert einige Konstanten von
CheckDataType Instanzen, die dazu dienen, die Art der Daten zu
definieren, auf denen ein Check beruht. Jede Konstante entspricht dabei einem der
verfügbaren 'Check' Knoten von QF-Test.
Außer seiner Funktion als Identifikator hat ein CheckDataType keine
public Attribute oder Methoden und Sie können keine neuen CheckDataType
Objekte erstellen. Wenn Sie einen Check implementieren wollen, der nicht zu den
verfügbaren Datentypen passt, müssen Sie Ihre Daten entsprechend konvertieren, z.B. in
einen String. Folgende CheckDataType Konstanten sind definiert:
- STRING
-
Ein einzelner String. Entspricht dem 'Check Text' Knoten.
- STRING_LIST
-
Eine Liste von Strings, wie die Zellen einer Tabellenspalte. Entspricht dem
'Check Elemente' Knoten.
- SELECTABLE_STRING_LIST
-
Eine Liste von selektierbaren Strings, wie die Elemente einer Liste. Entspricht dem
'Check selektierbare Elemente' Knoten.
- BOOLEAN
-
Ein Boolean Zustand, entweder true oder false. Entspricht dem
'Check Boolean' Knoten.
- GEOMETRY
-
Ein Satz von 4 Integer Werten für X und Y-Koordinaten, Breite und Höhe. Nicht alle
müssen definiert sein. Entspricht dem 'Check Geometrie' Knoten.
- IMAGE
-
Ein Abbild einer ganzen Komponente, eines Unterelements oder einer Region darin.
Entspricht dem 'Check Abbild' Knoten.
Die Klasse de.qfs.apps.qftest.shared.data.check.CheckData und ihre
Unterklassen, alle aus demselben Package, komplettieren das Checker API.
Ein CheckData Objekt kapselt die eigentlichen Daten für einen Check und
muss von der Methode Checker.getCheckData() zurückgeliefert werden.
Hiermit werden die Daten zwischen QF-Test und dem SUT ausgetauscht. Für jeden
CheckDataType gibt es eine zugehörige Unterklasse von
CheckData. Sie müssen nur deren Konstruktoren kennen, also führen wir
auch nur diese auf:
| |
|
|
| |
StringCheckData(String identifier, String value) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
value |
Der Wert des Checks, ein String.
|
| |
BooleanCheckData(String identifier, boolean value) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
value |
Der Wert des Checks, ein Boolean Zustand.
|
| |
StringItemsCheckData(String identifier, String[] values) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
values |
Der Wert des Checks, ein Array von Strings.
|
| |
SelectableItemsCheckData(String identifier, Object[][] values) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
values |
Der Wert des Checks, ein Array von Arrays mit einem String und einem Boolean für
"regexp" und einem Boolean für "selected".
|
| |
GeometryCheckData(String identifier, int x, int y, int width, int height) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
x |
Die X-Koordinate für den Check.
|
y |
Die Y-Koordinate für den Check.
|
width |
Die Breite für den Check.
|
height |
Die Höhe für den Check.
|
| |
ImageCheckData(String identifier, ImageRep image, int xOffset, int yOffset,
int subX, int subY, int subWidth, int subHeight) |
| Parameter |
identifier |
Der Bezeichner des Checktyps. Sollte normalerweise dem Bezeichner des
type Arguments entsprechen, das an Checker.getCheckData
übergeben wurde.
|
image |
Das Abbild für den Check. Näheres hierzu unter Abschnitt 39.7.
|
xOffset |
Ein optionaler X-Offset.
|
yOffset |
Ein optionaler Y-Offset.
|
subX |
Die X-Koordinate einer optionalen Check-Region.
|
subY |
Die Y-Koordinate einer optionalen Check-Region.
|
subWidth |
Die Breite einer optionalen Check-Region.
|
subHeight |
Die Höhe einer optionalen Check-Region.
|
| |
|
| |
Darüber hinaus kann für ein ImageCheckData optional ein Algorithmus definiert werden.
| |
|
|
| |
void setAlgorithm(String algorithm) |
| |
|
| |
Wenn Ihr Checker implementiert und instanziiert ist, muss er bei der
CheckerRegistry registriert werden. Die Klasse
de.qfs.apps.qftest.extensions.checks.CheckerRegistry bietet hierzu
folgende Methoden:
| |
|
|
| |
static CheckerRegistry instance() |
| Rückgabewert | Die CheckerRegistry Singleton Instanz. |
| |
void registerChecker(Object element, Checker checker) |
| Parameter |
element |
Das GUI Element für das registriert wird.
|
checker |
Der zu registrierende Checker.
|
| |
void unregisterChecker(Object element, Checker checker) |
| Parameter |
element |
Das GUI Element für das entfernt wird.
|
checker |
Der zu entfernende Checker.
|
| |
void registerChecker(String clazz, Checker checker) |
| Parameter |
clazz |
Der Name der Klasse für die registriert wird.
|
checker |
Der zu registrierende Checker.
|
| |
void unregisterChecker(String clazz, Checker checker) |
| Parameter |
clazz |
Der Name der Klasse für die entfernt wird.
|
checker |
Der zu entfernende Checker.
|
| |
|
| |
Das folgende Jython 'SUT Skript' zeigt, wie man alles zu einem eigenen
Checker zusammenfügt. Nehmen wir an, Sie haben eine Java Swing Anwendung und
möchten alle Labels in einem Panel gleichzeitig überprüfen. Dazu müssen Sie über
alle Komponenten im Panel und deren Kind-Komponenten iterieren, dabei die
Label-Komponenten identifizieren und eine Liste mit den enthaltenen Texten
generieren. In QF-Test Notation heißt das, Sie brauchen einen
CheckDataType.STRING_LIST Checktyp und müssen die Daten in einem
StringItemsCheckData Objekt zurückliefern:
|
|
from de.qfs.apps.qftest.extensions import ResolverRegistry
from de.qfs.apps.qftest.extensions.checks import CheckerRegistry, \
Checker, DefaultCheckType, CheckDataType
from de.qfs.apps.qftest.extensions.items import ItemRegistry
from de.qfs.apps.qftest.shared.data.check import StringItemsCheckData
from de.qfs.lib.util import Pair
from java.lang import String
import jarray
componentClass = "javax.swing.JPanel"
allLabelsCheckType = DefaultCheckType("AllLabels",
CheckDataType.STRING_LIST,
"Alle Labels im Panel")
class AllLabelsChecker(Checker):
def __init__(self):
pass
def getSupportedCheckTypes(self, com, item):
return jarray.array([allLabelsCheckType], DefaultCheckType)
def getCheckData(self, com, item, checkType):
if allLabelsCheckType.getIdentifier() == checkType.getIdentifier():
labels = self._findLabels(com)
labels = map(lambda l: l.getText(), labels)
values = jarray.array(labels, String)
return StringItemsCheckData(checkType.getIdentifier(), values)
return None
def getCheckDataAndItem(self, com, item, checkType):
data = self.getCheckData(com, item, checkType)
if data is None:
return None
return Pair(data, None)
def _findLabels(self, com, labels=None):
if labels is None:
labels = []
if ResolverRegistry.instance().isInstance(com, "javax.swing.JLabel"):
labels.append(com)
for c in com.getComponents():
self._findLabels(c, labels)
return labels
def unregister():
try:
CheckerRegistry.instance().unregisterChecker(
componentClass, allLabelsChecker)
except:
pass
def register():
unregister()
global allLabelsChecker
allLabelsChecker = AllLabelsChecker()
CheckerRegistry.instance().registerChecker(
componentClass, allLabelsChecker)
register() |
|
|
| | Beispiel 39.10: Alle Labels in einem Panel checken | |
Nach Ausführung des Skripts findet man einen neuen Eintrag "Alle Labels im Panel" im
Checktyp Menü, sobald man im Checkaufnahmemodus mit der rechten Maustaste auf eine
JPanel Komponente klickt (cf. Abschnitt 5.3). Wenn
Sie den allLabelsChecker überall in Ihrer Clientanwendung verwenden
möchten, können Sie das obige 'SUT Skript' hinter den 'Warten auf Client'
Knoten in der 'Vorbereitung' stellen. Ansonsten können Sie den Checker auch nach
Bedarf registrieren und später in einem anderen 'SUT Skript' wieder
entfernen:
|
|
from de.qfs.apps.qftest.extensions.checks import CheckerRegistry
global allLabelsChecker
def unregister():
try:
CheckerRegistry.instance().unregisterChecker(
"javax.swing.JPanel", allLabelsChecker)
except:
pass
unregister() |
|
|
| | Beispiel 39.11: Den Label Checker entfernen | |