Besondere Unterstützung für verschiedene Web-Komponentenbibliotheken

Modernen Web-Anwendungen sind oft sehr interaktiv und kommen vom Look&Feel her schon fast an Desktop-Applikationen heran. Hinter diesen Anwendungen steckt allerdings ein ganzer Zoo von Frameworks, auf denen diese basieren. Jedes davon setzt eigene Schwerpunkte und kommt mit einem eigenen Satz von Widgets. Solche Webframeworks stellen für QF-Test und jedes andere automatisierte Testwerkzeug aus folgenden Gründen ein Problem dar:

  • Die Komponentenhierarchie wird automatisch aus abstrakten Widgets wie Button oder List generiert. Ein Widget wird dabei oft mittels diverser <DIV> Knoten implementiert. Dies führt zu einer sehr tief verschachtelten Hierarchie mit geringer Struktur.
  • IDs werden entweder gar nicht zugewiesen oder automatisch generiert, was für Regressionstests noch problematischer ist.
  • Die asynchrone Kommunikation mit dem Webserver und die dynamische Erstellung von DOM Knoten kann Probleme beim Timing verursachen.

Es gibt kein Allheilmittel, mit dem sich diese Probleme generisch lösen lassen. In vielen Fällen kann QF-Test trotzdem ohne weiteres Zutun mit Webframeworks interagieren. Dabei sind Wiedererkennung und Performanz allerdings nicht ideal. Optimale Testbarkeit kann nur mit Hilfe von Spezialfunktionen erreicht werden, die genau auf ein Webframework zugeschnitten sind und sich dessen Eigenheiten zu Nutze machen.

Video Das Video 'Die Explosion der Komplexität in der Web Testautomatisierung eindämmen' zeigt eindrucksvoll die Reduktion tief geschachtelter DOM-Strukturen durch QF-Test.

Für eine große Anzahl von Webframeworks bietet QF-Test optimierte CustomWebResolver:

Framework NameWebseiteKurzname
Angular Materialmaterial.angular.ioangular
Ext JSsencha.com/products/extjsextjs
Fluent UI Reactdeveloper.microsoft.com/en-us/fluentui#/fluentui
Flutter Webflutter.dev/multi-platform/webflutter
Google Web Toolkit (GWT)gwtproject.orggwt
ICEfacesicesoft.orgicefaces
jQuery UIjqueryui.comjqueryui
jQuery EasyUIjeasyui.comjeasyui
Kendo UI for jQuerywww.telerik.com/kendo-jquery-uikendoui
Prime Facesprimefaces.orgprimefaces
Qooxdooqooxdoo.orgqooxdoo
Rich Ajax Platform (RAP)eclipse.org/raprap
RichFacesjboss.org/richfacesrichfaces
Smart GWTsmartclient.comsmartgwt
Vaadinvaadin.comvaadin
W3C ARIAw3.org/WAI/ARIA/apgaria
ZKzkoss.orgzk
Tabelle 49.7:  Unterstützte Webframeworks

Der angegebene Kurzname kann in 'CustomWebResolver installieren' Knoten in der Kategorie base angegeben werden, siehe Abschnitt 49.1.2.3. QF-Test ist sogar in der Lage, automatisch festzustellen, ob Ihre Web-Anwendung eines dieser Frameworks benutzt und einen passenden Resolver, wie unten beschrieben, einzuhängen. Verwenden Sie dazu den Kurznamen autodetect.

Konzepte für Webframework-Resolver

Ein Webframework-Resolver besteht aus verschiedenen Resolvern und anderen Funktionen, die speziell für ein bestimmtes Framework entwickelt werden. Vor allem versucht QF-Test, den DOM-Knoten Klassen zuzuweisen, die den zugehörigen abstrakten Widgets entsprechen und Knoten auf Zwischenebenen, die nur ein Detail der Framework-Implementierung sind, aus der Hierarchie herauszufiltern. Die Attribute 'Name', 'Merkmal' und 'Weiteres Merkmal' werden passend zum Framework ermittelt und Events werden so auf den korrekten DOM-Knoten wiedergegeben, dass dies möglichst exakt einer Aktion von einem echten Anwender entspricht. Diese Maßnahmen reduzieren die Hierarchie der Komponenten drastisch und erhöhen Performanz und Zuverlässigkeit der Wiedererkennung und Wiedergabe gleichermaßen. Zudem werden Timing und Synchronisation besonders unterstützt.

Zwangsläufig unterscheiden sich Komponenten und Events für eine Web-Anwendung mit und ohne aktiviertem Framework Resolver signifikant und sind nicht zueinander kompatibel. Daher sollte die Entscheidung, ob ein Framework Resolver verwendet wird, so früh wie möglich getroffen werden. Andernfalls müssen entweder bestehende Tests neu implementiert werden, nachdem der Resolver aktiviert wird oder Tests mit und ohne Resolver müssen sauber voneinander getrennt werden. Wenn ein Resolver für Ihre Anwendung verfügbar ist, sollten Sie ihn praktisch immer auch einsetzen, außer Ihre Tests sind bereits zu umfangreich, weitgehend vollständig und stabil.

Die Implementierung eines Webframework Resolvers ist ein fortlaufender Prozess. Wenn ein Webframework weiterentwickelt wird, so muss evtl. auch der zugehörige CustomWebResolver angepasst werden. Daher sind die eingebauten CustomWebResolver mit einer Versionsnummer versehen, welche der Versionnummer des Frameworks entspricht, für welche der Resolver ursprünglich entworfen wurde. So lange es nicht zu inkompatiblen Änderungen kommt, kann dieser CustomWebResolver auch für neuere Versionen des Frameworks verwendet werden.

Ältere CustomWebResolver in QF-Test setzen noch auf ein Versionsschema auf, welches von der Version des Web-Frameworks entkoppelt ist. Bei Aktualisierungen wird das neue Versionsschema verwendet.

Webframework-Resolver werden über den 'CustomWebResolver installieren' Knoten aktiviert, bei dem Sie auch die zu verwendende Version mit "." getrennt angeben können. Sie können wahlweise nur die Major Version angeben, in welchem Fall QF-Test die höchste verfügbare Medium.Minor Version für diese Major Version verwendet. Dies ist üblicherweise die beste Option und wird in der mit Hilfe des Schnellstart-Assistenten erstellten Startsequenz verwendet (vgl. Kapitel 3). Alternativ können Sie die Major.Medium Version festlegen, oder sogar die exakte Major.Medium.Minor Version und so Ihre Tests mit der Version des Resolvers ausführen, mit der sie erstellt wurden.

Eindeutige Bezeichner setzen

Jedes Webframework hat seine eigene Methoden, um eindeutige IDs zu vergeben. In diesem Abschnitt finden Sie die entsprechenden Methoden für die unterstützten Frameworks von QF-Test:

Angular

Die einfachste Variante ist es, das Attribut 'ID' <div id="myId"/> für alle notwendigen Komponenten zu setzen.

Ext JS

IDs können mittels folgendem Code gesetzt werden:
var container = Ext.create('Ext.container.Container', {
id: 'MyContainerId',
... });
.

Als Alternative können Sie auch container.getEl().set({ 'qfs-id': 'myId' }); aufrufen. In diesem Fall müssen Sie allerdings einen NameResolver implementieren, der 'qfs-id' als Namen für QF-Test setzt.

GWT

Die einfachste Variante ist die Methode widget.getElement().setId("myId"); für die erzeugten Elemente aufzurufen.

Alternativ können Sie auch widget.ensureDebugId("myId") aufrufen. Allerdings müssen Sie in diesem Fall die Datei xxx.gwt.xml anpassen, damit diese IDs auch wirklich gesetzt werden. Hierfür müssen Sie <inherits name="com.google.gwt.user.Debug"/> eintragen.

Es ist auch möglich ein eigenes Attribut 'qfs-id' für die Identifikation zu setzen. Hierfür rufen Sie die Methode setAttribute("qfs-id", "myId") auf. Dieses Attribut kann nun mittels NameResolver für QF-Test verwendet werden.

ICEfaces

Die einfachste Variante ist es, das Attribut 'ID' <p:inputText id="myId"/> für alle notwendigen Komponenten in der xhtml Definition zu setzen.

jQuery UI

Die einfachste Variante ist es, das Attribut 'ID' <p:inputText id="myId"/> für alle notwendigen Komponenten zu setzen, bei einem existierenden Element wie folgt: $(element).attr("id","myId");

jQuery EasyUI

Die einfachste Variante ist es, das Attribut 'ID' <p:inputText id="myId"/> für alle notwendigen Komponenten zu setzen.

Kendo UI für jQuery

Sie müssen das Attribut 'ID' im Sourcecode oder über den grafischen Editor setzen.

PrimeFaces

Die einfachste Variante ist es, das Attribut 'ID' <p:inputText id="myId"/> für alle notwendigen Komponenten in der xhtml Definition zu setzen.

Qooxdoo

Es gibt keinen Standardweg. Sie können entweder ein eigenes Attribut in der Generierung des DOMs an die Knoten oder eine Eigenschaft an die setData Methode des Qooxdoo Widgets hängen. Diese Eigenschaft können Sie dann per Resolver auswerten.

RAP

Ab RAP Version 2.2 wird ein Name, der mit widget.setData("name", "myId") vergeben wird, genau wie bei SWT direkt von QF-Test ausgewertet. Das Feld kann nur benutzt werden wenn es zuvor über WidgetUtil.registerDataKeys("name"); registriert wurde.

Für RAP Versionen älter als 3.0.0 funktioniert auch die folgende Technik, die aber nicht empfohlen wird, da sie vom SWT Standard abweicht und zuätzlich erfordert, den Webserver mit einer besonderen Option zu starten.:

Rufen Sie die Methode widget.setData(WidgetUtil.CUSTOM_WIDGET_ID, "myId"); für jedes notwendige Element auf.

Nun müssen Sie noch Ihre Webserver Umgebung mit folgendem zusätzlichen Parameter starten -Dorg.eclipse.rap.rwt.enableUITests=true.

Bitte beachten: Der VM Parameter wurde ab RAP 2.0 umbenannt, für RAP Versionen vor 2.0 lautet er -Dorg.eclipse.rwt.enableUITests=true.

RichFaces

Sie müssen das Attribut 'ID' im Sourcecode oder über den grafischen Editor setzen.

Smart GWT

Die einfachste Variante ist es, die Methode widget.setID("id") für alle notwendigen Komponenten aufzurufen.

Vaadin

Die einfachste Variante ist es, die Methode widget.setId("id") (widget.setDebugId("id") für Vaadin Version < 7) für alle notwendigen Komponenten aufzurufen.

Sie können auch eine eigene Stylesheet Klasse mittels widget.setStyleName("qfs-id=myId") hinzufügen. Diese muss dann in einem NameResolver für QF-Test ausgewertet werden.

ZK

QF-Test verwendet die Widget-ID, welche auch in den zul Dateien verwendet wird. Daher sollten die meisten IDs nutzbar sein.

Das ZK Framework bietet auch einen eigenen IDGenerator an, um IDs zu vergeben. Dies kann allerdings ziemlich aufwendig sein, hier ist es besser sich auf die Standardalgorithmen von QF-Test zu verlassen.