Die kniffligen Fälle beim Testen – GUI

Unit Tests der GUI? Das automatisierte Testen der GUI (grafical user interface) einer Desktop Anwendung ist auf den ersten Blick eine größere Herausforderung. Doch mit ein paar simplen Tricks kommt man bereits sehr weit. Ich stelle Ihnen im folgenden einige einfache Möglichkeiten anhand des folgenden Beispiels vor.

Automatisierte Tests GUIDie Abbildung zeigt eine simple UI, die eine Liste von Adressen anzeigt. Im unteren Bereich befindet sich eine CheckBox, die den daneben stehenden Button beeinflusst. Das Beispiel ist konstruiert, um daran einige Techniken zu erklären. Ich habe es mit WPF erstellt. Die Techniken lassen sich problemlos auf WinForms übertragen.

MVVM – Model View ViewModel

Es kommt ein View nebst ViewModel und Data Binding zum Einsatz. Da die Werte in der Tabelle nicht verändert werden können, habe ich darauf verzichtet, im ViewModel Adresse das Interface INotifyPropertyChanged zu implementieren.

In den folgenden Listings sehen Sie den Xaml Code, das ViewModel Adresse sowie die Code Behind Datei.

Den Dialog mit Daten anzeigen

Ein erster halb-automatisierter Unit Test sorgt zunächst einmal dafür, dass der Dialog mit Daten gefüllt und dann angezeigt wird. Im realen Projekt ersparen Sie sich mit Hilfe solcher Tests, dass Sie die Anwendung starten und an die entsprechende Stelle navigieren müssen. In komplexen Anwendungen bedeutet das eine große Zeitersparnis. Es müssen keine Beispieldaten in den Datenbanken hergestellt werden, etc. Programmatisch lassen sich solche Testfälle viel besser lösen. Insbesondere kann ein Dialog so bereits getestet werden, bevor er in die Anwendung integriert wird.

Der Unit Test trägt neben dem obligatorischen Test Attribute noch das Attribut Explicit, damit er nicht beim Ausführen aller Tests anspringt. Da der Test den Dialog mit ShowDialog öffnet, bleibt er solange am Bildschirm stehen, bis Sie ihn wieder schließen. Dieser Test ist eben nur halb-automatisiert: es werden automatisiert Testdaten vorbereitet und an den Dialog übergeben. Dann wird der Dialog geöffnet und bleibt zur Inaugenscheinnahme am Bildschirm stehen. Damit das technisch funktioniert, muss das Attribut Apartment(ApartmentState.STA) ergänzt werden, da WPF andernfalls meckert.

Testen, ob ein Button einen Event auslöst

Der folgende Unit Test überprüft, ob beim Betätigen des Buttons der erwartete Event ausgelöst wird. Auch dieser Test ist halb-automatisch. Im Test wird in der Arrange Phase eine Lambda Expression an den Event gebunden, die eine MessageBox anzeigt. Auf diese Weise kann ich den Test starten, auf den Button drücken und dann beobachten, ob die MessageBox angezeigt wird. Interessanter werden solche Tests, wenn beim Event Parameter mitgeliefert werden. Die können dann in der Nachricht der MessageBox angezeigt werden, um so zu prüfen, ob die erwarteten Werte geliefert werden.

Solche halb-automatischen Tests sind eine Übergangslösung in Legacy Code Projekten. Statt mit F5 die Anwendung zu starten und komplett manuell zu testen, lassen sich auf diese Weise einige Abläufe automatisieren. Wirklich rund wird die Sache, wenn der Test vollständig automatisiert abläuft, also auch ein Assert enthält, um eine Annahme zu überprüfen.

Automatisierter Test

Dieser Test läuft nun komplett automatisiert. An den Event des Buttons wird eine Lambda Expression gebunden, die einen Zähler inkrementiert. Nun soll der Button gedrückt werden, um dann zu prüfen, ob der Zähler auf 1 steht. Würde ich jetzt den Dialog mit ShowDialog öffnen, würde die Testausführung unterbrochen, bis der Dialog geschlossen wird. Folglich müsste der Dialog auf einem eigenen Thread geöffnet werden. Ferner bliebe dann noch die Frage offen, wie der Button programmatisch gedrückt werden kann. Ich verwende eine viel einfachere Lösung: ich rufe im Test die Methode auf, die in der UI am Button Click Event hängt. Das folgende Listing zeigt noch einmal den relevanten Ausschnitt aus der Code Behind Datei:

Um die Methode ButtonClickHandler im Test erreichen zu können, habe ich sie auf internal gesetzt. Details zum Thema Sichtbarkeit finden Sie in meinem früheren Blogbeitrag über die Sichtbarkeit in Tests.

Nach dem gleichen Schema kann ich nun automatisiert prüfen, ob beim Anhaken der CheckBox der Zustand des Buttons modifiziert wird.

Hier prüfe ich zunächst, ob der Button initial aktiviert ist. Anschließend simuliere ich im Test das Anklicken der CheckBox, in dem ich den Zustand IsChecked setze und dann den Handler CheckBoxClickHandler aufrufe, der am Click Event der CheckBox hängt. So kann ich dann anschließend prüfen, ob der Button wie erwartet modifiziert wurde.

Fazit

Selbstredend gehört solche Logik nicht in den View. „Richtig“ wäre es, ein ViewModel zu verwenden, welches diese Logik enthält. Das ViewModel ist dann einfach automatisiert testbar und beeinflusst den View mittels Data Binding. Im Falle von Legacy Code ist aber eben nicht alles „richtig“ gemacht worden, so dass die gezeigten Techniken dann helfen können, die Logik in der GUI durch Unit Tests automatisiert zu testen.

Schreibe einen Kommentar

Schnellstart Unit Tests

Stellen Sie die Korrektheit Ihrer Implementation automatisiert sicher durch Unit Tests. Starten Sie noch heute! In diesem Cheatsheet finden Sie die wichtigsten Details zu NUnit, MSTest und CppUnit, die Sie für einen schnellen Start benötigen. Auch zum Nachschlagen von selten genutzten Features hilfreich.

CheatSheet Unit Tests mit NUnit

Nachschlagen aller relevanter Details zu Unit Tests:

  • Grundlagen: Wie ist ein Test aufgebaut?
  • Wie werden Tests ausgeführt?
  • Assert: viele Beispiele zur Syntax.
  • Datengetriebene Tests
  • Wie teste ich interne Details?
  • Wie können Testdateien verwendet werden?
  • Welche Referenzen werden benötigt?

Gewinnen Sie die Kontrolle über Ihren Code zurück!

Schnellstart Mikado Methode

Ihre Codebasis ist Ihnen außer Kontrolle geraten? Undurchsichtige Abhängigkeiten erschweren Ihre Änderungen? Automatisierte Tests sind nicht vorhanden? Komplexe Refactorings werden nie fertig?

Komplexe Refactorings umsetzen mit der Mikado Methode
  • Gewinnen Sie die Kontrolle über Ihre Legacy Codebasis zurück
  • Lernen Sie die Mikado Methode.
  • Zerlegen Sie komplexe Refactorings Schritt für Schritt.
  • Enthält den Ablauf und Tipps zu den einzelnen Schritten der Mikado Methode.