UI-Tests überprüfen die korrekte Darstellung und Interaktion der Elemente der Benutzeroberfläche einer mobilen App — Schaltflächen, Textfelder, Listen und Navigationskomponenten. Im Gegensatz zu Modultests, die die Geschäftslogik prüfen, simulieren UI-Tests Benutzeraktionen: Berührungen, Wischbewegungen, Texteingabe und überprüfen die Reaktion der Oberfläche. Laut einer Studie von Android Developers, 2024 decken UI-Tests 70% der kritischen Benutzerszenarien ab und ermöglichen die Erkennung von Layoutfehlern, die logischen Prüfungen nicht zugänglich sind.
Wichtige Punkte
UI-Tests sind eine Art automatisierter Überprüfung, bei der der Testcode mit der grafischen Oberfläche der App genauso interagiert, wie es ein echter Benutzer tun würde. Der Test findet ein Element auf dem Bildschirm — eine Schaltfläche, ein Textfeld, eine Liste — führt eine Aktion darauf aus und überprüft die erwartete Reaktion der Oberfläche. Nach der Eingabe eines falschen Passworts prüft ein UI-Test beispielsweise, ob auf dem Bildschirm eine Fehlermeldung mit korrektem Text erscheint.
Der Hauptunterschied zwischen UI-Tests und anderen Automatisierungsarten besteht darin, dass sie über die Accessibility-Schicht des Betriebssystems und nicht über die internen APIs der App arbeiten. Das bedeutet, dass UI-Tests die Oberfläche genauso sehen wie ein Benutzer und ein Screenreader. Dadurch überprüfen UI-Tests nicht nur die Funktionalität, sondern auch die Barrierefreiheit der Elemente — die Einhaltung der WCAG-Anforderungen.
Laut der JetBrains Developer Ecosystem 2023-Umfrage verwenden 58% der mobilen Teams UI-Tests in ihrer CI/CD-Pipeline. Die durchschnittliche UI-Testabdeckung in kommerziellen Projekten beträgt 30–40% der App-Bildschirme. Projekte mit UI-Tests erhalten 25% weniger negative Bewertungen in App-Stores, die mit Oberflächenabstürzen zusammenhängen.
Der Hauptunterschied zwischen UI-Tests und Modultests ist die Abstraktionsebene. Modultests arbeiten mit einzelnen Klassen und Funktionen, die vom Android- oder iOS-Framework isoliert sind. Sie werden auf der JVM (für Android) ohne Emulator ausgeführt und dauern Millisekunden. UI-Tests werden auf einem echten Gerät oder Emulator ausgeführt, interagieren mit Systemdiensten und benötigen Sekunden oder Minuten pro Szenario.
Auch die Zielgruppe der Tests unterscheidet sich. UI-Tests überprüfen vollständige Benutzerszenarien — Registrierung, Bestellaufgabe, Suche. Modultests decken die Geschäftslogik ab: Berechnungen, Validierung, Datentransformation. Ein UI-Test prüft nicht die Korrektheit der Steuerberechnung — er prüft, ob der Gesamtbetrag auf dem Bildschirm angezeigt wird. Die Berechnung selbst wird durch einen Modultest überprüft.
Laut Google Testing Blog (2020) folgt das optimale Testverhältnis in einem Projekt der Testpyramidenregel: 70% Modultests, 20% Integrationstests und 10% UI-Tests. Eine Verletzung dieses Verhältnisses zugunsten von UI-Tests führt zu erhöhter Ausführungszeit und Zerbrechlichkeit der Testsuite, da UI-Tests empfindlich auf Änderungen im Bildschirmlayout reagieren.
Für Android ist das dominierende Framework Espresso — eine Bibliothek von Google, die in AndroidX Test integriert ist. Espresso synchronisiert sich automatisch mit dem UI-Thread und wartet auf den Abschluss von Animationen und Hintergrundaufgaben, bevor die nächste Prüfung ausgeführt wird. Für Jetpack Compose wird die Erweiterung Compose UI Test verwendet, die über semantische Knoten statt über traditionelle View-Identifikatoren arbeitet.
Für iOS ist das Hauptwerkzeug XCUITest, das Teil von Xcode ist. Die Tests werden in Swift geschrieben und verwenden Accessibility-Identifikatoren zum Auffinden von Elementen. XCUITest unterstützt die Testaufzeichnung über die Record-Funktion und die Integration mit CI-Systemen über xcodebuild. Für plattformübergreifende Projekte wird Appium verwendet, das auf dem WebDriver-Protokoll basiert und die Ausführung derselben Tests auf Android und iOS mit minimalen Codeänderungen ermöglicht.
Espresso arbeitet mit dem traditionellen View-System über onView und Ressourcen-ID-Identifikatoren. Compose UI Test verwendet eine semantische Schicht, die Tests weniger abhängig von der View-Hierarchie macht. Zum Beispiel die Suche nach einer Schaltfläche in Espresso: onView(withId(R.id.submit)), in Compose: onNodeWithTag(“submit”). Compose-Tests verarbeiten die Rekomposition automatisch und erfordern keine expliziten Wartezeiten auf den Ruhezustand.
XCUITest verwendet XCUIApplication als Einstiegspunkt. Jedes Oberflächenelement wird über Accessibility-Eigenschaften gefunden: accessibilityIdentifier für den programmatischen Zugriff und accessibilityLabel für VoiceOver. Das Framework unterstützt die Testaufzeichnung über die Record-Funktion von Xcode — der Entwickler führt Aktionen auf dem Simulator aus, und Xcode generiert den Testcode. Fertige Tests werden über xcodebuild test ausgeführt.
Appium basiert auf dem WebDriver-Protokoll und unterstützt jede Sprache: Java, Python, JavaScript. Die Elementfindungsstrategien umfassen id, xpath, class name und accessibility id. Appium erfordert die Installation eines Servers und die Konfiguration von Desired Capabilities — platformName, deviceName, appPackage. Eine Alternative ist Maestro, das YAML-Szenarien verwendet und keine Kompilierung von Testcode erfordert.
Betrachten wir UI-Tests für dasselbe Szenario — Anmeldung in der App — mit drei verschiedenen Frameworks: Espresso für Android, XCUITest für iOS und Appium für den plattformübergreifenden Ansatz. Szenario: Login und Passwort eingeben, Anmeldebutton drücken, die Anzeige der Begrüßungsnachricht überprüfen.
Ein Espresso-Test verwendet onView zum Auffinden eines Elements anhand seiner ID und perform zum Ausführen einer Aktion. Die check-Methode mit dem isDisplayed-Matcher bestätigt, dass das Element auf dem Bildschirm sichtbar ist.
@RunWith(AndroidJUnit4::class)
class LoginUiTest {
@Rule
@JvmField
val composeTestRule = createComposeRule()
@Test
fun login_withValidCredentials_showsWelcome() {
composeTestRule
.onNodeWithTag("emailField")
.performTextInput("user@example.com")
composeTestRule
.onNodeWithTag("passwordField")
.performTextInput("secret123")
composeTestRule
.onNodeWithTag("loginButton")
.performClick()
composeTestRule
.onNodeWithText("Willkommen, Benutzer!")
.assertIsDisplayed()
}
}
XCUITest verwendet XCUIApplication, um über Accessibility-Identifikatoren auf Oberflächenelemente zuzugreifen. Die Methoden tap() und exists bieten Interaktion und Überprüfung.
class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testLogin_withValidCredentials_showsWelcome() {
app.textFields["emailField"].tap()
app.textFields["emailField"].typeText("user@example.com")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("secret123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
}
}
Der erste Grundsatz — verwenden Sie Accessibility-Identifikatoren anstelle von Textbeschriftungen zum Auffinden von Elementen. Der Text einer Schaltfläche kann sich bei der Lokalisierung ändern, während der Identifikator stabil bleibt. In Android ist dies die Eigenschaft contentDescription, in iOS — accessibilityIdentifier. Dieser Ansatz macht Tests unabhängig von der Oberflächensprache und reduziert die Wartungskosten bei Änderungen im Copywriting.
Vermeiden Sie sleep() und feste Verzögerungen — verwenden Sie die integrierten Wartemechanismen des Frameworks. Espresso wartet automatisch auf den Abschluss von Animationen und Hintergrundaufgaben. XCUITest bietet XCTAssertTrue mit Timeout. Explizite Pausen machen Tests langsamer und instabiler, besonders auf langsamen Geräten in einer CI-Umgebung.
Gruppieren Sie Tests nach Kritikalität: Smoke-Tests (3–5 Hauptszenarien) werden bei jedem Commit ausgeführt, die vollständige UI-Testsuite vor dem Release. Laut Google Testing Blog (2022) reduzieren UI-Tests, die in CI mehr als 30 Minuten dauern, die Ausführungshäufigkeit um 40%, was ihre Effektivität als Werkzeug zur frühzeitigen Erkennung von Regressionen verringert.
UI-Tests haben mehrere Einschränkungen. Empfindlichkeit gegenüber Layoutänderungen: Eine Änderung des Identifikators, der Hierarchie oder des Elementtyps bricht den Test, selbst wenn die Funktionalität unverändert bleibt. Die Lösung ist die Verwendung des Page Object-Musters, das Elementselektoren in separaten Klassen zentralisiert. Bei Layoutänderungen wird nur eine Page Object-Datei korrigiert, nicht Dutzende von Tests.
Ausführungszeit: Die Ausführung auf einem echten Gerät oder Emulator dauert 10–50 Mal länger als ein Modultest. Die Lösung besteht darin, UI-Tests parallel auf mehreren Geräten über Firebase Test Lab oder AWS Device Farm auszuführen. Flakiness (Unzuverlässigkeit) ist ein häufiges Problem bei CI-Läufen, verursacht durch Animationen, Netzwerkverzögerungen oder den Emulatorzustand. Zur Bekämpfung von Flakiness werden automatische Wiederholungen fehlgeschlagener Tests und Stabilitätsanalysen für jedes Testszenario eingesetzt.
Häufig gestellte Fragen
Für einen durchschnittlichen Bildschirm reichen 3–5 UI-Tests: Happy Path, Fehlervalidierung, leerer Zustand, Orientierungswechsel und Accessibility-Prüfung. Komplexe Bildschirme mit mehreren Zuständen — Bestellformulare, Einstellungen — können 10–15 Tests für eine vollständige Abdeckung der wichtigsten Szenarien erfordern.
Ja, Appium und Maestro ermöglichen die Ausführung derselben Szenarien auf beiden Plattformen. Native Frameworks — Espresso und XCUITest — bieten jedoch bessere Stabilität, Geschwindigkeit und Zugriff auf plattformspezifische Funktionen, die über WebDriver-Proxys nicht verfügbar sind.
Für Compose wird die Bibliothek Compose UI Test mit semantischen Matchern verwendet: onNodeWithText, onNodeWithTag, onNodeWithContentDescription. Die semantische Schicht von Compose abstrahiert die View-Hierarchie, was Tests im Vergleich zu traditionellem Espresso für das View-System weniger anfällig macht.
Basis-UI-Tests werden auf Emulatoren in CI ausgeführt — das ist schnell und günstig. Die endgültige Überprüfung vor dem Release sollte auf physischen Geräten über Firebase Test Lab erfolgen, um die Eigenschaften echter Hardware zu berücksichtigen: verschiedene Auflösungen, OS-Versionen und Leistung.
Verwenden Sie parallele Ausführung auf mehreren Geräten, deaktivieren Sie Animationen auf dem Emulator über die Entwickleroptionen, bauen Sie eine modulare Testarchitektur auf und führen Sie die Smoke-Suite bei jedem Commit aus, während der vollständige Regressionstest nach Zeitplan oder vor dem Release läuft.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch