let’s dev GmbH & Co. KG - Die Marke für wegweisende Individualsoftware

Blog

Top!

let’s dev | Scroll to top
let’s dev | Scroll to next content item

Hello

let’s dev | Scroll to previous content item
let’s dev Blog | iOS UI Tests
by Nicolas
12. November 2020

iOS UI Tests

Automatisierte Tests sind essentiell bei der Entwicklung hochwertiger Apps. Gerade beim Entwickeln der Business Logik ist es wichtig, diese mit Unit Tests abzudecken, um bei späteren Änderungen sicher sein zu können, dass auch alles so funktioniert, wie beabsichtigt.

Neben den Unit Tests gibt es noch eine weitere Form der automatisierten Tests, die User Interface Tests, kurz UI Tests. Während Unit Tests sich wirklich auf eine abgegrenzte Einheit oder Funktion konzentrieren, simulieren UI Tests das tatsächliche Verhalten eines Nutzers, der mit der App interagiert. Dadurch sind allerdings auch deutlich mehr Dinge zu beachten, damit UI Tests genau wie Unit Tests deterministisch sind, also bei jeder Durchführung zum gleichen Ergebnis führen.

Dies lässt sich gut am Beispiel einer iOS-App zeigen. In dieser Beispiel-App gibt es drei Funktionen, die sich alle mit UI Tests testen lassen. Wird ein Text eingegeben, erscheint dieser nach Bestätigung in der Navigation Bar. Drückt man den Button, erscheint ein Alert mit dem Titel „Good Morning“. Zuletzt lässt sich über den Switch einstellen, ob man den Button drücken kann oder nicht.

UI Test Example

Der erste UI-Test

Zum Schreiben eines UI Tests kann wie bei Unit Tests auf Apples XCTest Framework zurückgegriffen werden. Im Gegensatz zu Unit Tests muss man in jedem Test Case allerdings die App starten und beschreiben, wie mit welchen Elementen interagiert werden soll.

Das Starten der App geschieht folgendermaßen:

let app = XCUIApplication()
app.launch()

Auf die einzelnen UI-Elemente lässt sich nun über die Variable app zugreifen. Der Button im obigen Beispiel lässt sich beispielsweise über den Titel auslesen.

let button = app.buttons["Show Alert"]

Der Nachteil dieser Art und Weise ist allerdings, dass man den UI Test aktualisieren müsste, wenn sich aus gewissen Gründen der Titel des Buttons ändern würde. Um dies zu vermeiden, lässt sich auf jedem UIKit-Element der accessibilityIdentifier setzen, der genau für UI Tests gedacht ist. Dies kann entweder im Code geschehen oder man setzt ihn im Storyboard bzw. Xib-File im Identity Inspector der jeweiligen View. Analog dazu gibt es in SwiftUI den Modifier .accessibility(identifier:).

Gibt man dem Button nun den accessibilityIdentifier „Example.Button“, kann im UI Test über diesen String darauf zugegriffen werden.

let button = app.buttons["Example.Button"]

Um gewisse Bedingungen zu testen verwendet man, wie auch in Unit Tests, die Assertions, welche XCTest anbietet. Damit sichergestellt wird, dass der Button gedrückt werden kann, kann man wie folgt vorgehen:

XCTAssertTrue(button.isEnabled)

Im letzten Schritt unseres ersten UI Tests soll geprüft werden, dass der Button nach Deaktivieren des Switches nicht mehr gedrückt werden kann. Dazu wird der Switch anhand seines vergebenen accessibilityIdentifier ausgelesen und einmal betätigt. Schließlich folgt die Prüfung, ob der Button nicht mehr aktiv ist.

let uiSwitch = app.switches["Example.Switch"]
uiSwitch.tap()
XCTAssertFalse(button.isEnabled)

Xcode bietet auch die Möglichkeit an, bestimmte Interaktionen, die getestet werden sollen, aufzunehmen. Das bedeutet, man kann im Simulator mit UI-Elementen interagieren und der Recorder übersetzt dies in Code für einen UI Test. In den meisten Fällen ist dies nicht besonders zuverlässig und der Code ist meist komplizierter als notwendig, es kann jedoch als Einstiegshilfe dienen. Eine Aufnahme kann über den roten Record-Button unterhalb des Editors gestartet werden, wenn sich der Cursor in einer Testmethode befindet.

Alerts und Navigation Bar

Nach der Fertigstellung des ersten UI Tests können wir nach dem gleichen Muster auch für unsere beiden weiteren Szenarien vorgehen.

Um zu testen, dass der Button ein Alert auslöst, wird dieser wieder ausgelesen und schließlich über die tap()-Methode gedrückt. Ein Alert lässt sich mittels seines Titels auslesen, allerdings kann man hier auch auf die element-Property zurückgreifen, die man stets nutzen kann, wenn es nur ein Element des entsprechenden Typs gibt. Wenn z. B. nur ein Button auf dem Screen zu sehen ist, könnte man auch über app.buttons.element auf den Button zugreifen. Ähnlich funktioniert auch die firstElement property, die das erste passende Element zurück liefert, wenn es beispielsweise keine Rolle spielt, welches konkrete Element des Typs benötigt wird.

Nun können wir mittels der exists-Property sicherstellen, dass das Alert auch wirklich angezeigt wird und schließlich über den OK-Button wieder schließen. So sieht das ganze am Ende so aus:

let app = XCUIApplication()
app.launch()

let button = app.buttons["Example.Button"]
button.tap()

let alert = app.alerts.element
XCTAssertTrue(alert.exists)
alert.buttons["OK"].tap()

Im letzten UI Test soll sichergestellt werden, dass der Text, welcher in das Textfeld eingegeben wird, nach Bestätigung in der Navigation Bar angezeigt wird. Auch Textfelder lassen sich über die app-Variable auslesen. Bei der Eingabe des Texts sind ein paar Dinge zu beachten. Zunächst muss das Textfeld den Fokus erhalten, indem wir es mittels tap() auswählen. Daraufhin lässt sich mit der typeText()-Funktion ein beliebiger String eingeben. Damit der Text in die Navigation Bar geschrieben wird, muss der Return-Button der Tastatur betätigt werden. An der Stelle ist es im UI Test extrem wichtig, im Simulator das Software Keyboard aktiviert zu haben (I/O —> Keyboard —> Toggle Software Keyboard), da sonst der Return-Button nicht gefunden werden kann.

Die Navigation Bar kann schließlich ebenfalls über ihren Titel ausgelesen werden, woraufhin geprüft wird, ob diese auch wirklich vorhanden ist.

let app = XCUIApplication()
app.launch()

let textField = app.textFields["Example.TextField"]
textField.tap()
textField.typeText("Good Morning")
app.keyboards.buttons["Return"].tap()

let navigationBar = app.navigationBars["Good Morning"]
XCTAssertTrue(navigationBar.exists)

Stolpersteine

Ein wichtiger Punkt, der bei UI Tests zu beachten ist, ist Flakiness. Man spricht davon, dass ein Test flaky ist, wenn er manchmal erfolgreich durchläuft, ein anderes Mal aber nicht. Dies kann viele Gründe haben. Ein Grund kann sein, dass ein State aus einem vorherigen Test nicht zurückgesetzt wurde und die App nicht im korrekten Zustand ist, sodass z. B. ein Onboarding Screen, der nur beim ersten App Start angezeigt wird, beim 2. Lauf des UI Tests nicht mehr angezeigt wird.

Eine gängige Art und Weise, dies zu vermeiden, sind Launch Arguments. Diese können der App vor dem Start im UI-Test mitgegeben und im Code der App ausgelesen werden. So kann z. B. auf diesem Weg definiert werden, dass wir die App bei jedem Durchlauf zurücksetzen möchten:

let app = XCUIApplication()
app.launchArguments = ["reset-app"]
app.launch()

Im AppDelegate oder SceneDelegate kann daraufhin geprüft werden, ob das reset-Argument vorhanden ist und dann gegebenenfalls die Datenbank oder UserDefaults zurückgesetzt werden, je nach App Szenario.

if CommandLine.arguments.contains("reset-app") {
resetApp()
}

Im Gegensatz zu Unit Tests, bei welchen Netzwerkaufrufe meist nicht wirklich ausgeführt werden, werden diese in UI Tests ganz normal ausgeführt. Das kann allerdings ebenfalls dazu führen, dass Elemente, die z. B. erst nach Laden der Daten vom Server angezeigt werden, im UI Test nicht direkt verfügbar sind.

Wird also ein Button erst angezeigt, nachdem eine Anfrage an den Server erfolgreich durchgeführt wurde, kann dies im UI Test mittels eines Delays berücksichtigt werden. Über die Methode waitForExistence kann ein Timeout definiert werden, der im Grunde aussagt, dass die Dauer des Timeouts abgewartet wird, dass das Element existiert. Erst wenn nach Ablauf des Timeouts die Bedingung nicht erfüllt ist, gilt der Test als fehlgeschlagen.

XCTAssertTrue(timelineCell.waitForExistence(timeout: 2))

Launch Arguments und die waitForExistence-Methode sind sehr nützlich, um sicherzustellen, dass UI Tests deterministisch sind. Erst, wenn jeder Durchlauf des Tests zum gleichen Ergebnis führt, ist er wirklich von Nutzen.

Wrapping Up

Wie gezeigt wurde, sind UI Tests ein sehr hilfreiches Mittel zur Qualitätssicherung einer App. Dabei können zum einen bestimmte Workflows getestet werden, aber es lässt sich auch sicherstellen, dass die UI auf verschiedensten Gerätegrößen gut aussieht. Zudem lässt sich im Grunde jede Interaktion und Geste des Benutzers abbilden. Lediglich WebViews oder Szenarien, bei welchen auf die Sensoren des Geräts zugegriffen werden, sind weniger geeignet.

Da es mehr Aufwand benötigt, UI Tests zu schreiben und durchzuführen als z. B. Unit Tests, sollte man ein gewisses Gefühl dafür entwickeln, an welchen Stellen der Einsatz Sinn macht.

Referenzen

Weitere Artikel aus unserem Blog

let’s dev Blog | Adobe Max - Zum ersten Mal online

Corporate

Adobe Max - Zum ersten Mal online

by Julia

2020-10-29

Weiterlesen
let’s dev Blog | CAN2BLE

Technical

CAN2BLE

by Raphael

2020-09-24

Weiterlesen
let’s dev Blog | Mensch und Computer 2020 - Digitaler Wandel im Fluss der Zeit

Corporate

Mensch und Computer 2020 - Digitaler Wandel im Fluss der Zeit

by UX Team

2020-09-18

Weiterlesen
let’s dev Blog | Neumorphism – Eine neue Ära des User Interface Design?

Technical

Neumorphism – Eine neue Ära des User Interface Design?

by Julian

2020-08-13

Weiterlesen
let’s dev Blog | UX Research Teil 3 – UX Methoden

Technical

UX Research Teil 3 – UX Methoden

by Elena

2020-05-28

Weiterlesen
let’s dev Blog | UX Research Teil 2 - Was ist UCD und was hat User Research damit zu tun?

Technical

UX Research Teil 2 - Was ist UCD und was hat User Research damit zu tun?

by Elena

2020-04-23

Weiterlesen
let’s dev Blog | go-digital fördert Einrichtung von Home Office Arbeitsplätzen

Corporate

go-digital fördert Einrichtung von Home Office Arbeitsplätzen

by Karl

2020-03-19

Weiterlesen
let’s dev Blog | Google Passes - Karten­verwaltung auf  Android-Geräten

Technical

Google Passes - Karten­verwaltung auf Android-Geräten

by Michelle

2020-03-12

Weiterlesen
let’s dev Blog | 100% Code-Coverage bei Software Tests – eine sinnvolle Zielsetzung?

Technical

100% Code-Coverage bei Software Tests – eine sinnvolle Zielsetzung?

by Raphael

2020-03-06

Weiterlesen
let’s dev Blog | Swift UI - Einfache und schnelle Umsetzung von User Interfaces

Technical

Swift UI - Einfache und schnelle Umsetzung von User Interfaces

by Tobias

2020-03-02

Weiterlesen
let’s dev Blog | Im Dialog mit den Wirtschafts­junioren – Spannende Einblicke in die Unternehmens­gründung und die digitale Trans­formation

Corporate

Im Dialog mit den Wirtschafts­junioren – Spannende Einblicke in die Unternehmens­gründung und die digitale Trans­formation

by Julian

2020-02-27

Weiterlesen
let’s dev Blog | Vereinfachtes Testen von iOS Push Notifications im Simulator mit Xcode 11.4

Technical

Vereinfachtes Testen von iOS Push Notifications im Simulator mit Xcode 11.4

by Manuel

2020-02-26

Weiterlesen
let’s dev Blog | Nationales Meeting des Konsortiums des SPEAR Forschungs­projektes bei let’s dev in Karlsruhe

Corporate

Nationales Meeting des Konsortiums des SPEAR Forschungs­projektes bei let’s dev in Karlsruhe

by Karl

2020-01-27

Weiterlesen
let’s dev Blog | UX Research Teil 1 – Warum User Research so wichtig ist

Technical

UX Research Teil 1 – Warum User Research so wichtig ist

by Elena

2020-01-23

Weiterlesen
let’s dev Blog | Dark Mode

Technical

Dark Mode

by Elisa

2020-01-09

Weiterlesen
let’s dev Blog | Wir wünschen frohe Weihnachten – Und einen guten Start ins neue Jahr!

Corporate

Wir wünschen frohe Weihnachten – Und einen guten Start ins neue Jahr!

by Julian

2019-12-20

Weiterlesen
let’s dev Blog | Austausch zum Thema Digitalisierung mit dem Business Club Luxemburg in der Botschaft von Luxemburg in Berlin

Corporate

Austausch zum Thema Digitalisierung mit dem Business Club Luxemburg in der Botschaft von Luxemburg in Berlin

by Karl

2019-12-17

Weiterlesen
let’s dev Blog | DaSoMan auf der Internet+ Expo in Foshan (China)

Corporate

DaSoMan auf der Internet+ Expo in Foshan (China)

by Karl

2019-12-13

Weiterlesen
let’s dev Blog | Google Play Console: Pre-Launch Berichte

Technical

Google Play Console: Pre-Launch Berichte

by Fabian

2019-12-11

Weiterlesen
let’s dev Blog | DevFest 2019 in Hamburg

Technical

DevFest 2019 in Hamburg

by Julian

2019-12-05

Weiterlesen
let’s dev Blog | Vernissage digitale Kunst im Medientheater der Humboldt Universität Berlin

Corporate

Vernissage digitale Kunst im Medientheater der Humboldt Universität Berlin

by Karl

2019-11-21

Weiterlesen
let’s dev Blog | World Usability Day 2019 in Karlsruhe – let’s dev unterstützt als Hauptsponsor

Corporate

World Usability Day 2019 in Karlsruhe – let’s dev unterstützt als Hauptsponsor

by Aileen

2019-11-11

Weiterlesen
let’s dev Blog | Ausgeschlachtet - Tag der offenen Türen auf dem Alten Schlachthof Karlsruhe 2019

Corporate

Ausgeschlachtet - Tag der offenen Türen auf dem Alten Schlachthof Karlsruhe 2019

by Julian

2019-09-26

Weiterlesen
let’s dev Blog | Mensch und Computer 2019 - Konferenz zu User Experience und Usability in Hamburg

Corporate

Mensch und Computer 2019 - Konferenz zu User Experience und Usability in Hamburg

by Elena

2019-09-17

Weiterlesen
let’s dev Blog | Business und Enterprise App Verteilung unter iOS

Technical

Business und Enterprise App Verteilung unter iOS

by Aileen

2019-08-05

Weiterlesen
let’s dev Blog | Digital Transformation - Chances and Challenges in the Automotive Industry, Agriculture and New Technologies

Corporate

Digital Transformation - Chances and Challenges in the Automotive Industry, Agriculture and New Technologies

by Karl

2019-07-17

Weiterlesen
let’s dev Blog | let’s dev unterstützt Läuferinnen und Läufer bei der 7. KIT Meisterschaft

Corporate

let’s dev unterstützt Läuferinnen und Läufer bei der 7. KIT Meisterschaft

by Karl

2019-07-05

Weiterlesen
let’s dev Blog | Automatisiertes Testing von C++ Code mit Google Test und Google Mock – Teil 2

Technical

Automatisiertes Testing von C++ Code mit Google Test und Google Mock – Teil 2

by Arne

2019-06-13

Weiterlesen
let’s dev Blog | Apple WWDC 2019: Das sind die Highlights der Keynote

Technical

Apple WWDC 2019: Das sind die Highlights der Keynote

by Nicolas

2019-06-05

Weiterlesen
let’s dev Blog | App Builders 2019

Technical

App Builders 2019

by Nicolas

2019-05-23

Weiterlesen
let’s dev Blog | Offizielle Eröffnung des Festigungs- und Expansionszentrums (FUX)

Corporate

Offizielle Eröffnung des Festigungs- und Expansionszentrums (FUX)

by Helena

2019-04-15

Weiterlesen
let’s dev Blog | Delegation aus Nottingham zu Besuch auf dem Alten Schlachthof in Karlsruhe

Corporate

Delegation aus Nottingham zu Besuch auf dem Alten Schlachthof in Karlsruhe

by Helena

2019-04-14

Weiterlesen
let’s dev Blog | Es ist soweit: Wir ziehen um!

Corporate

Es ist soweit: Wir ziehen um!

by Helena

2019-03-26

Weiterlesen
let’s dev Blog | Automatisiertes Testing von C++ Code mit Frameworks – Teil 1

Technical

Automatisiertes Testing von C++ Code mit Frameworks – Teil 1

by Arne

2019-02-20

Weiterlesen
let’s dev Blog | Die App im Google Play Store

Technical

Die App im Google Play Store

by Elisa

2019-01-24

Weiterlesen
let’s dev Blog | „UX Day“ 2018

Corporate

„UX Day“ 2018

by Aileen

2018-12-17

Weiterlesen
let’s dev Blog | let’s dev unterstützt SG Siemens Volleyballer aus Karlsruhe

Corporate

let’s dev unterstützt SG Siemens Volleyballer aus Karlsruhe

by Helena

2018-12-04

Weiterlesen
let’s dev Blog | KMU gestalten die Digitalisierung – Mittelstandskonferenz 2018

Corporate

KMU gestalten die Digitalisierung – Mittelstandskonferenz 2018

by Helena

2018-11-12

Weiterlesen
let’s dev Blog | Apple Wallet

Technical

Apple Wallet

by Maik

2018-10-26

Weiterlesen
let’s dev Blog | „Mensch und Computer“ 2018

Corporate

„Mensch und Computer“ 2018

by Judith

2018-09-24

Weiterlesen
let’s dev Blog | State Design Pattern in Android

Technical

State Design Pattern in Android

by Thomas

2018-09-17

Weiterlesen
let’s dev Blog | let’s dev ist autorisiertes Beraterunternehmen im Förderprogramm „go-digital“

Corporate

let’s dev ist autorisiertes Beraterunternehmen im Förderprogramm „go-digital“

by Helena

2018-09-01

Weiterlesen
let’s dev Blog | App Design & Development Conference 2018

Corporate

App Design & Development Conference 2018

by Helena

2018-08-14

Weiterlesen
let’s dev Blog | iOS 12: Die Top-Neuerungen im Überblick

Technical

iOS 12: Die Top-Neuerungen im Überblick

by Nicolas

2018-07-17

Weiterlesen
let’s dev Blog | let’s dev auf der CEBIT

Corporate

let’s dev auf der CEBIT

by Karl

2018-06-11

Weiterlesen
let’s dev Blog | Einführung in User Interface (UI) Tests mit Espresso

Technical

Einführung in User Interface (UI) Tests mit Espresso

by Raphael

2018-06-07

Weiterlesen
let’s dev Blog | Die App im Apple App Store: welche Informationen werden benötigt?

Technical

Die App im Apple App Store: welche Informationen werden benötigt?

by Aileen

2018-04-27

Weiterlesen
let’s dev Blog | Smart Pointer in C++

Technical

Smart Pointer in C++

by Matthias

2018-04-01

Weiterlesen
let’s dev Blog | User Interface Design für das iPhone X: alle Neuerungen auf einen Blick

Technical

User Interface Design für das iPhone X: alle Neuerungen auf einen Blick

by Helena

2018-02-07

Weiterlesen
let’s dev Blog | WebVR – Virtual Reality Experience im Browser mit dem A-Frame Framework

Technical

WebVR – Virtual Reality Experience im Browser mit dem A-Frame Framework

by Judith

2018-01-10

Weiterlesen
let’s dev Blog | Open Data Hackathon der Deutschen Bahn

Corporate

Open Data Hackathon der Deutschen Bahn

by Karl

2015-03-31

Weiterlesen
let’s dev Blog | Blur-Effekte unter iOS 7

Technical

Blur-Effekte unter iOS 7

by Katja

2014-04-24

Weiterlesen
let’s dev Blog | Beyond App Store – Distribution von iOS-Anwendungen

Technical

Beyond App Store – Distribution von iOS-Anwendungen

by Karl

2012-08-27

Weiterlesen
let’s dev Blog | Frontend-Architektur – Model View Presenter und Message Bus

Technical

Frontend-Architektur – Model View Presenter und Message Bus

by Karl

2011-03-08

Weiterlesen