26. Mai 2020
ComponentNotFoundExceptions analysieren
Im oberen Bild kann man einen Mausklick Knoten sehen, welcher auf die Komponente (benannt mFile) geht. Immer wenn ein Aktion (z.B. ein Mausklick) oder eine Überprüfung wiedergegeben wird muss QF-Test zuerst die entsprechende Komponente in der Anwendung suchen.
Sollte es QF-Test nicht möglich sein die gewünschte Komponente in der Anwendung zu finden, so wird eine ComponentNotFoundException geworfen.
Der folgende Blogartikel erklärt die verschiedenen Schritte, mithilfe derer eine solche Exception analysiert werden kann.
Überprüfen ob die Komponente verfügbar war
Auch wenn es eventuell naiv klingt, als erstes sollte überprüft werden, ob die Zielkomponente während der Ausführung der Aktion oder Verifikation zur Verfügung stand - also zum Zeitpunkt der Ausführung nicht später.
Wann immer eine Exception auftritt, loggt QF-Test (standardmäßig) ein Bildschirmabbild. Über den "In Protokoll springen" Button erreicht man das Protokoll, in welchem diese Bildschirmabbilder abgespeichert werden. Sollte man den Fehlerhinweisdialog bereits geschlossen haben, so kann man das Protokoll mithilfe der Tastenkombination Strg+L öffnen. Im Protokoll kann man dann mithilfe des "Nächsten Fehler finden"-Icon (siehe Bildschirmabbild unten) schnell zu der zu analysierenden Exception springen. Jetzt schaut man, ob die beim Fehler enthaltenen Bildschirmabbilder die gewünschte Komponente aufzeigen. Sollte die Komponente auf einem der Bildschirmabbilder sichtbar sein, so hilft der nächste Abschnitt "Wie überprüfe ich, warum QF-Test meine Komponente nicht findet, obwohl die Komponente in der Anwendung verfügbar ist".
Sollte die Komponente auf den Bildschirmabbildern nicht sichtbar sein, so überprüfen Sie:
- Ob Ihre Anwendung eventuell mehr Zeit braucht bis die Komponente sichtbar wird
Es kann sein, dass QF-Test zu ungeduldig ist und versucht die Zielkomponente zu finden, obwohl die Komponente noch nicht sichtbar/verfügbar ist. Anstatt der Zielkomponente zeigt die Anwendung dann möglicherweise eine "Ich bin beschäftigt" Warteanimation an (z.B. eine Progressbar).
Häufig sieht man hier, dass eine hinreichend große Wartezeit im 'Verzögerung vorher' oder im 'Verzögerung nachher' Attribut spezifizieren wird, um QF-Test zum Warten anzuregen. Auch wenn diese Lösung funktioniert, sollte dies nicht die bevorzugte Lösung sein, da QF-Test dann in jedem Fall die angegebene Zeitspanne abwartet. Um die Testausführungsgeschwindigkeit zu erhöhen, ist es besser einen 'Warten auf Komponente', einen 'Warten auf Laden des Dokuments' oder einen 'Warten auf Verschwinden' Knoten zu nehmen (Mit letzterem kann man darauf Warten, dass die Progressbar verschwindet).
Um einen 'Warten auf Komponente'-Knoten einzufügen bietet sich folgendes Vorgehen an: Man kopiert den Knoten und fügt ihn erneut ein. (Jetzt hat man den Knoten zweimal). Anschließend, rechter Mausklick auf den ersten Knoten → Knoten konvertieren in → Warten auf Komponente.
- Wenn die Aktion/Verifikation eine nicht immer erscheinende Komponente als Ziel hat
Hier kommt die Anwendung manchmal mit einer Komponente die behandelt werden muss. So etwas kann z.B. eine Nachricht wie "Verbinden zum Server fehlgeschlagen" sein, welche sporadisch nach bestimmten Aktionen auftritt (und bestimmte weitere Aktionen nötig macht).
Wenn Sie also Aktionen haben welche nur ab und an ausgeführt werden müssen (in diesem Fall z.B. der Klick auf den OK-Button des Fehler-Dialogs) dann kann man ein try/catch-Konstrukt verwenden. Ein solches Konstrukt weißt QF-Test an, jeglichen Fehler zu ignorieren, welcher bei der Ausführung einer Knotenabfolge auftritt. Um ein solches Konstrukt einzufügen, markieren Sie die fehlschlagenden Knoten, Rechtsklick → Knoten einpacken in → Try.
Alternativ kann ein 'If' Knoten verwendet werden, um zu überprüfen, ob die Zielkomponente vorhanden ist und die entsprechenden Aktionen ausgeführt werden müssen.
- Wenn Sie ein Aktionen/Verifikationen haben, welche nur möglich sind, wenn bestimmte Vorbedingungen erfüllt sind
Zum Beispiel kann es sein, dass eine Komponente nur verfügbar ist, sofern man sich angemeldet hat oder ähnliches.
Hier kann man (wie beim vorhergehenden Punkt) zwar ebenfalls mit try/catch Konstruktionen arbeiten, allerdings ist es in solchen Situationen häufig besser mithilfe von Abhängigkeit-Knoten die entsprechenden Vorbedingungen (in diesem Fall "User ist eingeloggt") sicherzustellen.
- Die Komponente muss sichtbar gescrollt werden.
Es kann sein, dass man zu seinem Test Logik hinzufügen muss, welche die entsprechende Komponente sichtbar scrollt. (Was ein interessantes Thema für einen weiteren Blogartikel ist.)
- Die Komponente ist nicht da, weil die zu testende Anwendung einen Bug enthält
Das heißt, dass die Komponente eigentlich an dieser Stelle verfügbar sein sollte - es irgendwie aber nicht ist. Zum Beispiel kann es sein nach einer fehlerhaften Eingabe eine Komponente mit einem Fehlerhinweis kommen soll. Diese Komponente aber nie erscheint.
In diesem Fall macht es Sinn mit dem Entwicklungsteam über verschiedene Verbesserungen an der Software zu reden ;)
- Die Zielkomponente wurde vom Entwicklungsteam entfernt.
Hier liegt ebenfalls ein Fall vor, den Sie intern klären sollten. Eventuell soll der Testfall entfernt oder neu geschrieben werden.
- Wenn die Komponente nicht angezeigt wird, weil die vorherige Aktion fehlgeschlagen ist
Diese Fall kommt selten vor. Allerdings sollte erwähnt werden, dass eine Komponente eventuell nicht gefunden wird, weil eine vorherige Aktion fehlgeschlagen ist (so zum Beispiel kann es sein dass der Mausklick fehlgeschlagen ist der den Dialog mit der Zielkomponente öffnet). Hier muss man dann schauen, warum diese Aktion fehlgeschlagen ist (ohne dass QF-Test dies gemerkt hat).
Wie überprüfe ich, warum QF-Test meine Komponente nicht findet, obwohl die Komponente in der Anwendung verfügbar ist
Um hier keine Missverständnisse aufkommen zu lassen, soll kurz umrissen werden, wie der QF-Test Komponentenenerkennungsalgorithmus funktioniert.
Das Attribut "QF-Test ID der Komponenten" verweist nicht direkt auf die gewünschte Zielkomponente. Stattdessen verweist diese Zeichenkette auf einen Knoten im Fenster und Komponenten Unterbaum. Dieser Knoten stellt die Eigenschaften bereitstellt, anhand derer die Komponente in der Anwendung gesucht werden soll. Wenn wir z.B. den obigen Mausklick nehmen:
Dann verweist dieser Mausklick (rechts auf den Knoten klicken → Komponente finden) auf folgenden Knoten:
Es sind die Informationen in diesem "Komponenten Knoten", welche vom Komponentenwiedererkennungsalgorithmus für die Wiedererkennung hergenommen werden. Die Zeichenkette "mFile" ist nur eine Referenz (Es steht Ihnen frei die QF-Test ID einer Komponente zu ändern, damit der Test lesbarer wird).
Der Grund, warum die Informationen für die Wiedererkennung an einer zentralen Stelle abgelegt werden, ist der folgende: Es kann sein, dass sich eine Komponente in Ihrer Anwendung so ändert, dass QF-Test diese nicht mehr wiedererkennt (z.B. wenn sich der Text eines Buttons von OK zu Weiter ändert. Auch wenn dies allein nicht unbedingt ausreichend ist). Allerdings kann es sein, dass Sie eine beliebige Anzahl an Knoten haben, die auf diese Komponente verweisen (z.B. 500 Klicks auf diesen Button).
Dadurch, dass die Komponenteninformationen ausgelagert sind, muss nicht über die komplette Testsuite gegangen werden (und jeder einzelne Klick von OK zu Weiter geändert werden), sondern es reicht, wenn man den einen "Komponenten Knoten" entsprechend anpasst...
Wie Sie eventuell bereits wissen, verwendet QF-Test einen Wahrscheinlichkeitsalgorithmus, um die zu suchende Komponenten zu ermitteln. Und dass dieser Algorithmus die einzelnen Komponenten im Komponentenbaum nacheinander sucht. Das heißt, wenn Sie sich das obige Bild anschauen wird QF-Test zuerst das Fenster, dann die MenuBar und anschließend erst das MenuItem mFile suchen.
Da QF-Test zuerst die entsprechende Fensterkomponente, dann die nächste Komponente usw. sucht, müssen wir als erstes herausfinden, welche Komponente genau QF-Test nicht mehr erkennt. Ist es das Fenster selbst (z.B. weil der Windowtitel sich von "MeineAnwendung - version 1.0" zu "MeineAnwendung - version 2.0" geändert hat)? Oder findet QF-Test irgendeine der Zwischenkomponenten nicht mehr?
Wenn Sie die Möglichkeit haben, so können Sie durchaus einfach erneut einen Mausklick aufnehmen (vergessen Sie nur nicht die Aufnahme nach der Analyse zu löschen - andernfalls sammeln sich unter dem Fenster und Komponenten Knoten verschiedene Aufnahmen an). Durch einen Vergleich der existierenden Knoten mit den neu aufgenommenen Knoten kann man dann herausfinden, wo der Baum sich unterscheidet - und dadurch welche der Komponentendefinitionen QF-Test nicht in der Anwendung finden konnte.
Zum Beispiel wenn man den Klick erneut aufnimmt, erhält man:
Hier kann man sehen, dass die Fenster-Komponente immer noch dieselbe ist (schwarz markiert). Das heißt, dass QF-Test in der Lage ist die Fenster-Komponente zu identifizieren. Als nächstes kommt die MenuBar (rot markiert) und wie man sehen kann, gibt es zwei Komponentendefinitionen ... Das heißt, dass QF-Test nicht in der Lage ist die MenuBar Komponente zu finden.
Das Protokoll bietet ebenfalls die nötigen Informationen, um die sich unterscheidende Komponente herauszufinden. Im Falle einer ComponentNotFoundException wird nämlich eine Nachricht gespeichert, welche erklärt warum QF-Test nicht in der Lage war, eine entsprechende Komponente in der Anwendung zu finden:
Nachdem wir die Komponente identifiziert haben, können wir überprüfen, welches Knotenattribut sich geändert hat. Anschließend:
- wenn sich das Klasse Attribut geändert hat
Das Klassenattribut gibt den Typ der Komponente an, nach der QF-Test suchen soll. Hiermit kann man QF-Test z.B. anweisen, dass man nach einem Button, einer Liste, einer Textarea oder etwas ähnlichem sucht.
Es ist selten der Fall, dass sich die Komponentenklasse ändert (d.h. z.B. dass ein Button durch ein Label mit der selben Funktionalität ersetzt wird). Sollte dieser Fall bei Ihnen vorliegen, so hilft es, das Klassenattribut entsprechend der neuen Aufnahem abzuändern.
- wenn sich das Name Attribut geändert hat
Das Name Attribut ist das Attribut, welches mit den größten Einfluss auf die Komponentenerkennung hat. Das Name-Attribut sollte eine eindeutige Identifikation der Komponente in der Anwendung ermöglichen.
Jede Komponente in Ihrer Anwendung kann von den Entwicklern eine derartige Identifikation bekommen. Allerdings sind diese Indentifikationen für den Anwender nicht sichtbar, weshalb Entwickler sich oft nicht die Mühe machen (auch wenn dies die Komponentenerkennungsstabilität deutlich verbessern kann). Manche Anwendungen missbrauchen diese Möglichkeit auch und speichern hier anderweitige, sich ändernde Daten.
Wenn Sie nur eine Komponente haben, dann können Sie ausprobieren, ob es hilft, wenn Sie das Namen-Attribut leeren. Sollten mehrere Komponenten hiervon betroffen sein, so kann man über einen NameResolver beeinflussen, was QF-Test (ob überhaupt) und was QF-Test als Name-Attribut einer Komponente aufnimmt und verwendet.
- wenn sich das Merkmal Attribut geändert hat
Das Merkmal Attribut verweist auf die für die Komponentenerkennung wichtigste Eigenschaft. Das kann z.B. der Text der Komponente sein (also z.B. OK im Falle eines OK-Buttons).
Sollte das Feature sich verändernde Teilzeichenketten aufweisen (z.B. wenn sich der Titel der Applikation ändern kann "MeineAnwendung Version 1.0" or "MeineAnwendung Version 2.0" und so weiter), dann kann man die "Als Regexp" Checkbox anklicken und anstatt dem Text dann einen regulären Ausdruck in dem Textfeld zugeben, sodass der reguläre Ausdruck dann immer das Merkmal matcht.
Mithilfe eines FeatureResolver ist es weiterhin möglich zu ändern, welche Eigenschaft einer Komponete QF-Test als Merkmal hernimmt/aufnimmt.
- wenn sich eine oder mehrere der Merkmale in der "weitere Merkmale" Tabelle geändert hat/haben
In dieser Tabelle werden weitere Merkmale zusammengefasst, anhand derer QF-Test die Komponente erkennen kann.
Man kann einen ExtraFeatureResolver benutzen, um hier weitere Merkmal hinzuzufügen oder um einzelne Merkmale aus dieser Tabelle zu entfernen. (Das Ganze ist analog zu den oben genannten NameResolver, FeatureResolver etc.).
- Sollten sich Geometrie oder Struktur geändert haben
Die Struktur / Geometrie wird von QF-Test nicht häufig für die Komponentenerkennung verwendet. Sollten hier Probleme auftreten, dann liegt meist der Fall vor, dass QF-Test keinen guten Namen oder kein gutes Merkmal hat, um die Komponente zuverlässig zu erkennen. In diesem Fall versucht QF-Test anhand der Geometrie / Strukturinformationen dennoch zu bestimmen, welche Komponente gemeint ist. Ein Beispiel: Angenommen man hat mehrere OK-Buttons in der Anwendung. Diese haben dann bei der Aufnahme die selbe Klasse (Button), keinen Namen (haben die Entwickler nicht vergeben), das gleiche Merkmal (OK) und die gleichen Extra-Merkmale. Dann entscheidet QF-Test anhand der Geometrie und/oder Struktur, welcher der in der Anwendung vorhandenen OK-Buttons gemeint ist.
Solange es also gute Name / Merkmal oder weitere Merkmale gibt, anhand derer QF-Test die Komponente erkennen kann, kann man Unterschiede hier ignorieren, korrigieren oder sogar den Inhalt dieser Textfelder löschen.
Allerdings, sollte QF-Test keinen guten Namen, kein gutes Merkmal und keine guten weiteren Merkmale haben, so macht es Sinn, sich die Zeit zu nehmen und zumindest einen der oben genannten Resolver zu implementieren. Das ist häufig besser als bei der Komponentenerkennung auf die Geometrie und/oder die Struktur zurückzugreifen. (Bei der Komponentenerkennung anhand von Geometriedaten gibt es einige Probleme, z.B. wenn die Tests auf verschiedenen Maschienen wiedergegeben werden, kommt es hier häufiger zu ComponentNotFoundExceptions, da sich die Geometrien der einzelenen Komponenten in der Anwendung, je nach Bildschirmgröße etc. ändern ...)
Hinweise
- Stellen Sie sicher, dass Ihre Tests auf einem nicht gesperrten, aktiven Desktop ausgeführt werden. Ansonsten kann es sein, dass an zufälligen Stellen Komponenten werden nicht gefunden Exceptions geworfen werden (und wenn man die Tests wiederholt, dann sind es andere Aktionen / Überprüfungen welche fehlschlagen).