Handbuch

32
Wie erreicht man eine robuste Komponentenerkennung?

Das wichtigste Feature eines GUI Testwerkzeuges ist die Wiedererkennung der grafischen Komponenten. QF-Test bietet hierfür jede Menge Konfigurationsmöglichkeiten. Dieses Kapitel gibt einen Überblick über die gebräuchlichsten Strategien und Einstellungen, um die Komponentenerkennung so stabil wie möglich zu gestalten.

Wir empfehlen auch, sich die Abschnitte Abschnitt 36.13 und Abschnitt 42.2 genauer anzuschauen.

Hinweis Sie müssen die Strategie zur Komponentenerkennung vor dem breiten Einsatz von QF-Test in Ihrem Projekt festlegen. Andernfalls kann die Wartung von Tests große Schwierigkeiten bereiten. Einige Denkanstöße hierzu finden Sie im Kapitel 29.

32.1
Benutzen der Standardeinstellungen

In den meisten Projekten können Sie mit der Standardeinstellung sehr gut arbeiten. Die Standardeinstellung benutzt für die Erkennung einer Komponente deren Namen, deren Klasse (Typ) und ebenso deren Hierarchie (Aufbau der Maske).

Mit diesen Einstellungen bekommen Sie Probleme, wenn

  • die Entwicklung keine eindeutigen Namen vergibt.
  • sich die Komponentenhierarchie, also der Maskenaufbau, stark ändert.
  • sich die Namen ändern (siehe Abschnitt 32.4).

Wenn die Entwicklung keine Namen vergibt, verwendet QF-Test eine errechnete Gesamtwahrscheinlichkeit aus mehreren Einflussfaktoren, wie einem Label oder dem Text eines Buttons oder der Geometrie der Komponente für die Wiedererkennung. Diese Berechnung ist ziemlich stabil, solange nur einige Eigenschaften der Komponente stabil bleiben, z.B. der Text eines Labels. Sie sollten allerdings darauf achten, dass für die Tests das SUT immer mit derselben Fenstergröße gestartet wird.

Die Standardeinstellung für Komponentenaufzeichnung sieht so aus:

Abbildung 32.1:  Standardeinstellung Komponentenaufzeichnung

Die Standardeinstellung für die Wiedererkennung beim Abspielen sieht so aus:

Abbildung 32.2:  Standardeinstellungen für die Wiedergabe
32.2
Die 'Name übertrifft alles' Einstellung benutzen

Wenn die Entwickler stabile und eindeutige Namen für alle wichtigen Komponenten eines Tests vergeben, z.B. für alle Buttons, Tabellen und Textfelder, dann können Sie die Wiedererkennungsoptionen auf 'Name übertrifft alles' setzen. Dies bringt den Vorteil, dass Sie nun die Komponenten direkt anhand deren Namen und des Fensters, in dem sich die Komponenten befindet, erkennen. Falls sich die GUI-Hierarchie des SUT ändert, wird das keine Auswirkung auf die Komponentenerkennung haben, da nur die Namen der eigentlichen Komponenten verwendet werden.

Mit dieser Einstellung bekommen Sie Probleme, wenn

  • die Entwicklung keine eindeutigen Namen vergibt.
  • sich die Namen ändern (siehe Abschnitt 32.4).

Die 'Name übertrifft alles' Einstellung für das Aufzeichnen sieht so aus:

Abbildung 32.3:  'Name übertrifft alles' Einstellung für die Aufzeichnung

Die 'Name übertrifft alles' Einstellung für das Abspielen sieht so aus:

Abbildung 32.4:  'Name übertrifft alles' Einstellung für das Abspielen
32.3
Verwendung von regulären Ausdrücken oder Arbeiten mit dynamischen Fenstertiteln

In vielen Applikationen werden Sie auf die Situation treffen, dass keine eindeutigen Namen seitens der Entwicklung vergeben wurden und QF-Test dieselben Komponenten immer wieder an unterschiedlichen Stellen aufzeichnet. Die Wiedergabe dieser aufgezeichneten Komponenten funktioniert dann meistens solange sich die Geometrie des Fensters nicht drastisch verändert.

In diesem Fall ist es wahrscheinlich, dass der Titel des Hauptfensters sich immer wieder ändert, z.B. kann der Titel die aktuelle Versionsnummer, den gerade eingeloggten Benutzer oder einen Dateinamen beinhalten. Wenn Sie Ihre Tests stabil halten wollen und die unterschiedlich aufgezeichneten Fenster als einen 'Fenster' Knoten unter dem 'Fenster und Komponenten' Knoten behandeln wollen, dann selektieren Sie den 'Fenster' Knoten und editieren Sie dessen 'Merkmal' Attribut. Dort ersetzen Sie den dynamischen Teil durch einen regulären Ausdruck und haken dabei die Checkbox 'Als Regexp' an. Nun sollten Ihre Tests wieder funktionieren.

Hier sehen Sie ein Beispiel für einen regulären Ausdruck für eine Komponente des JCarConfigurators, deren 'Merkmal' mit dem Wort 'Fahrzeuge' beginnt, aber danach einen beliebigen dynamischen Teil enthalten kann:

Abbildung 32.5:  Ein regulärer Ausdruck im 'Merkmal' Attribut

Reguläre Ausdrücke finden bei QF-Test an vielen Stellen Verwendung. Im Abschnitt 42.4 finden Sie detaillierte Informationen zu ihrer Verwendung.

Hinweis QF-Test IDs von Komponenten können, wie im Abschnitt 5.3 beschrieben, unter Zuhilfenahme des 'Merkmal' Attributs generiert werden. Da das 'QF-Test ID' Attribut nur ein künstliches Konzept ist, um Aktionen auf aufgezeichnete Komponenten abzubilden, kann es unter Umständen schön sein, wenn es zur besseren Lesbarkeit nachträglich geändert wird. QF-Test bieten die Möglichkeit, beim Umbenennen alle Referenzen automatisch anzupassen.

32.4
Beeinflussen von Namen mittels NameResolver

In GUI Testprojekten können Sie auf jede Menge interessanter Namenskonzepte für Komponenten stoßen. Manchmal haben die Komponenten keine Namen, aber die Tester kennen einen Algorithmus, um eindeutige Namen zu setzen. Ein anderes Mal existieren Namen, die sich aber von Zeit zu Zeit ändern, z.B. zeichnen Sie einen 'button1' beim ersten Mal auf und beim nächsten Mal heißt dieser Button plötzlich 'button2'. Eine andere Variante könnte sein, dass die aktuelle Versionsnummer des SUT im Namen des Hauptfensters steckt.

In solchen Fällen sollten Sie sich das NameResolver Interface von QF-Test genauer anschauen.

Ein NameResolver kann verwendet werden, um Namen aus der QF-Test Sicht zu ändern oder zu löschen. Diese Änderungen treffen dann nur für die QF-Test Sicht zu und ändern nichts am aktuellen Sourcecode.

Sie sollten über den Einsatz von NameResolver nachdenken, wenn:

  • das SUT dynamische Namen besitzt.
  • Sie einen Algorithmus kennen, um eindeutige Namen zu vergeben.
  • Sie Namen auf andere Namen setzen wollen, z.B. wegen einer neuen Version oder für das Testen in anderen Sprachen.
  • Sie die Namensgebung der Komponenten optimieren wollen, z.B. einige Teile ausschneiden, um lesbarere QF-Test IDs für Komponenten in QF-Test zu erhalten.

Wenn Sie eine Eindeutigkeit pro Fenster erreichen, können Sie darüber nachdenken die Standardeinstellungen auf 'Name übertrifft alles' zu setzen, siehe hierzu Abschnitt 32.2.

Hinweis Wenn es möglich ist, dass die Entwickler eindeutige und stabile Namen direkt vergeben, dann sollten es diese im Sourcecode tun, da die Entwickler am besten wissen, welche Komponenten angelegt werden. Das Implementieren eines NameResolvers kann eine sehr aufwendige und mühsame Aufgabe sein, besonders wenn sich das GUI stark ändert.

NameResolvers sind in Abschnitt 45.1.6 beschrieben.

32.5
Klassen von Komponenten

4.0+ QF-Test zeichnet so genannte generische Klassen auf. Diese Klassen sind technologieübergreifend gültig und somit unabhängig von den konkreten technischen Klassen.

Für eine Swing Komponente führt eine Beispielaufzeichnung zur generischen Klasse Button für jeden javax.swing.JButton, sogar dann, wenn von dieser Klasse abgeleitet wurde. Für die anderen Engines erhalten Sie ähnliche Aufzeichnungen für die entsprechenden Klassen des Toolkits. Zusätzlich sei erwähnt, dass dieses Konzept QF-Test erlaubt problemlos Tests mit obfuskierten Klassen zu erstellen, ohne dass Sie die Standardeinstellungen ändern müssen.

Während der Wiedergabe vergleicht QF-Test das aufgezeichnete 'Klassen' Attribut der Komponente mit jeder Klasse des Objektes im SUT. Deshalb kann QF-Test auch mit Änderungen von Klassennamen umgehen, so lange der Basistyp der selbe bleibt.

Sie finden im Abschnitt Abschnitt 5.4.1 eine genaue Beschreibung der generischen Klassen.

32.5.1
Umgehen von Klassenänderungen durch 'Nur Systemklassen aufzeichnen'

4.0+ Dieser Abschnitt ist nur relevant, wenn Sie mit einer älteren QF-Test Version als 4.0 arbeiten. Diese Versionen unterstützen das Konzept der generischen Klassen nicht.

Die Verwendung dieser Einstellung erlaubt es QF-Test nur Systemklassen der Komponenten aufzuzeichnen, anstatt der eigenen Klassennamen. Systemklassen sind javax.swing... und java.awt... Klassen für Java/Swing und org.eclipse.swt.widgets... Klassen für Java/SWT Applikationen.

Abbildung 32.6:  Option um nur Systemklassen aufzuzeichnen

Nur mit Systemklassen zu arbeiten, ermöglicht es Ihnen mit Ihren aufgezeichneten Komponenten weiterzuarbeiten, auch nach Re-factoring Schritten der Entwickler, wenn sich Klassennamen ändern. Des Weiteren können Sie auch Klassen, die mit Obfuscatoren verändert wurden, für die Tests verwenden.

In den meisten Fällen ist diese Option sehr hilfreich. Jedoch sollten Sie nicht mit dieser Option arbeiten, wenn die konkreten Klassen ein wichtiger Bestandteil Ihrer Komponentenerkennungsstrategie sind. Falls die Entwickler keine guten Namen gesetzt haben, allerdings unterschiedliche Klassen für bestimmte Container benutzen, dann kann QF-Test anhand dieser konkreten Klasse die Komponenten wiederum erkennen.

3.1+ Ein gemischter Ansatz ist mit dem Einsatz eines ClassNameResolvers möglich. ClassNameResolver können nützlich sein, wenn Sie nur für bestimmte Klassen Systemklassen aufzeichnen wollen, aber nicht für alle, z.B. nicht bei Drittanbieter Bibliotheken. Eine genaue Beschreibung finden Sie unter Abschnitt 45.1.7.

32.6
Nicht notwendige Aufzeichnungen ersparen oder generische Komponenten einsetzen

Bis jetzt haben wir Ansätze kennen gelernt, um die Wiedererkennung an unsere Bedürfnisse anzupassen. Jedoch müssen wir immer noch jede einzelne Komponenten aufzeichnen, die wir im Test verwenden wollen.

Sie können sich sicher vorstellen, dass es ein sehr mühsamer Akt ist, jede Komponente, die in einem Test verwendet werden könnte, aufzuzeichnen. Manchmal könnte das sogar nahezu unmöglich sein, z.B. wenn es sich ändernde Namen oder ändernde Labels gibt. Ein typischer Anwendungsfall hierfür ist das Testen von lokalisierten Anwendungen.

Eine andere Situation könnte der Einsatz eines GUI Frameworks bei der Entwicklung sein. Dieser Einsatz generiert jede Menge ähnlicher Dialoge, wo sich nur ein paar Komponenten unterscheiden. Aber Sie müssen jedes Mal jeden Bereich neu aufzeichnen, auch wenn Sie dies schon einmal gemacht haben - z.B. Navigationsbuttons in jedem Fenster, weil es sich immer um ein neues Fenster handelt.

QF-Test bietet nun die Möglichkeit, die Aufzeichnung drastisch zu reduzieren. Dieses Konzept wird als 'Generisches Komponenten Konzept' bezeichnet. Hierfür benutzen Sie Variablen in den Komponenteneigenschaften oder löschen einfach dynamische Teile daraus.

Ein allgemeiner Ansatz für das Generalisieren von Komponenten ist folgender:

  1. Zeichnen Sie einige Komponenten, die Sie generalisieren wollen, auf und vergleichen Sie diese.
  2. Erstellen Sie eine generische Komponente, die in der QF-Test ID 'generisch' enthält, damit Sie diese wiederfinden.
  3. Entfernen Sie alle Attribute, die Sie nicht für die Wiedererkennung verwenden wollen, aus dieser generischen Komponente.
  4. Legen Sie die Wiedererkennungseigenschaft fest, z.B: 'Name', 'Merkmal' oder 'Index'.
  5. Setzen Sie in diesem Attribut eine Variable, z.B. $(name).
  6. Um falsche Treffer zu vermeiden, deaktivieren Sie die Geometrieerkennung und setzen in den 'X' und 'Y' Attributen ein '-'.
  7. Spezifizieren Sie '@generic' im Attribut 'Bemerkung', damit diese Komponenten nicht unbeabsichtigt von der 'Ungenutzte Komponenten entfernen' Aktion gelöscht wird.
  8. Erstellen Sie eine Prozedur, um auf diese generische Komponente zuzugreifen und verwenden Sie die Variable/diese Variablen von vorhin als Parameter der Prozedur.

Hinweis Generische Komponenten sind sehr nützlich für das Abspielen von Tests, aber QF-Test verwendet diese nicht für die Aufzeichnung. Sie werden immer die konkreten Komponenten aufgezeichnet bekommen. Sie müssen daher nachträglich die konkreten Komponenten durch die generische ersetzen.

3.1+32.7
Optionen zur Laufzeit verändern

Seit QF-Test Version 3.1 ist es sogar möglich, die Wiedererkennungsoptionen zur Laufzeit zu ändern. Daher sind Sie nun vollkommen flexibel und können unterschiedliche Varianten für das SUT verwenden.

Optionen können entweder in einem 'Server Skript' oder 'SUT Skript' - hängt von der jeweiligen Option ab - und Aufruf von rc.setOption(OPTION_NAME, OPTION_VALUE) gesetzt werden. Sie finden eine Liste aller möglichen Optionen für die Aufnahme unter Abschnitt 35.2 und für das Abspielen unter Abschnitt 35.3.