Mobile App Testing

Artikel von Andreas Grabner

Wenn man Testing-Teams fragt, wie es um das Testen von mobilen Apps steht, kommt zu oft die Antwort, dass es keine guten Werkzeuge gibt, um das Testen zu automatisieren, und dass es schwer ist, auf allen möglichen Endgeräte zu testen. Stimmt das wirklich? Gibt es nicht mittlerweile genug Werkzeuge der Gerätehersteller, die Testen erleichtern? Muss man wirklich am Gerät selbst testen? Was sollte überhaupt getestet werden? Beschränkt man sich auf das Gerät alleine oder muss man die gesamte Anwendung inklusive Serverseite testen? Was, wenn Bugs übersehen werden, und gibt es eine Möglichkeit, Daten von den realen Benutzern zur Fehlerbehebung zu ermitteln?

Einen Schritt zurück: Um welche Art der Anwendung handelt es sich überhaupt?

Bevor man sich die Frage stellt, ob und wie mobile Anwendungen am besten getestet werden, gilt es zuerst einmal zu klären, ob es sich um Mobile-Web- oder Mobile-NativeAnwendungen handelt. Bei Mobile Native ist noch zu unterscheiden, ob es tatsächlich eine rein native Anwendung ist oder ob es sich „lediglich“ um eine Hybrid-Anwendung handelt, die ein Container für einen Browser ist und Webinhalte anzeigt – somit also einer mobilen Webanwendung gleichzusetzen ist. Viele dieser Hybrid-Anwendungen wurden entwickelt, um genau die Anwendungen in den App Stores zu platzieren, die von Endanwendern bevorzugt werden. Viele benutzen aber den nativen Teil, um Zugriff auf gewisse Features des Gerätes zu bekommen, zum Beispiel: GPS-Tracking, Zugriff auf den Bewegungssensor und auf die Kamera. Weitere Artikel zum Unterschied zwischen Mobile Web versus Mobile Native lassen sich leicht im Web finden, weshalb ich hier nicht weiter im Detail darauf eingehen werde.

Was muss getestet werden?

Sieht man sich in den App Stores die Kommentare zu schlecht bewerteten Apps an, kommt man schnell zu dem Schluss, dass es einige wenige Gründe gibt, warum Anwendungen abgestraft werden: Crashes, Bugs, schlechte Performance und Usability-Probleme. Da der Erfolg einer App stark davon abhängt, wie ihre Bewertung im App Store ist, sollte sich das Testen der App auch stark auf genau diese Bereiche fokussieren.

Crashes und Bugs

Bugs und Memory Leaks sind die Hauptgründe für Crashes. Aus diesem Grund ist es wichtig, die gesamte Funktionalität der Anwendung zu testen. Nur so kann sichergestellt werden, dass kein funktioneller Bug die Anwendung mit einer Exception zum Crashen bringt. Der beste Weg, um Bugs zu verhindern, ist, eine möglichst hohe Testabdeckung des Codes durch Unit- und Integrationstests zu erreichen. Crasht die Anwendung dennoch, so stellen sowohl Android als auch iOS detaillierte Crashreports zur Verfügung. Bei Problemen mit JavaScript-Fehlern – sowohl im reinen Mobile Web als auch im Hybrid-Betrieb – bekommt man durch die vom Betriebssystem zur Verfügung gestellten Crashreports nichts mit. Hier muss man sich selbst um das Logging kümmern, um diese Fehler zu entdecken. Da es bei vielen Anwendungen nicht möglich ist, alle Funktionen auf allen möglichen Geräten zu testen, ist es ratsam, einen Mechanismus vorzusehen, der es ermöglicht, Crashes von realen Usern einzusehen. So kann schneller und besser auf Probleme reagiert werden. Mehr dazu im Abschnitt „Es kann nicht alles getestet werden“.

Für Memory Leaks ist es wichtig, Langzeittests durchzuführen, da diese oft nur schleichend auftreten. Crashreports alleine helfen hier oft nur bedingt. Wichtig ist es, darauf zu achten, welche Funktionen der Anwendung eine hohe Speicherkapazität verbrauchen. Weiterhin muss berücksichtigt werden, dass mehrere Anwendungen auf einem Gerät installiert sind. Laufen andere Anwendungen, die ebenfalls viel Speicher benötigen, ist es möglich, dass die eigene Anwendung eher out of memory läuft oder durch den Speicherverbrauch anderer Anwendungen eingeschränkt wird. Daher ist es wichtig, dass diese Rahmenbedingungen beim Testen miteinbezogen werden, um eine realistische Testumgebung herzustellen. Mehr dazu im Abschnitt „Rahmenbedingungen einbeziehen“.

Performance

Ein Grund, warum die Wahl auf native anstelle von Webanwendungen fällt, ist das Argument Performance. Anstatt auf den JavaScriptInterpreten und die Rendering-Fähigkeiten des mobilen Browsers zu vertrauen, können native Anwendungen die Ressourcen des mobilen Gerätes optimaler verwenden. Obwohl diese Aussage natürlich stimmt, heißt dies nicht, dass mobile Webanwendungen per se langsamer sind. Die Weiterentwicklung der mobilen Browser, vor allem in Bezug auf Performance, war in den letzten Jahren beträchtlich. Die größten Performanceprobleme, die aktuell zu beobachten sind, werden nicht unbedingt durch langsame JavaScriptFunktionen verursacht. Vielmehr handelt es sich um Probleme beim Downloaden von großen Inhalten (nicht komprimierter Bilder, CSS-Dateien, JS-Dateien usw.) über langsame Verbindungen oder das ständige Neuberechnen des Layouts bei ineffektiver Verwendung von relativen Positionsangaben zwischen DOM-Elementen. Bei nativen Anwendungen sind es Requests mit großen Inhalten, die am Gerät zergliedert, zwischengespeichert und verarbeitet werden müssen. Aufwendige Algorithmen können die CPU schnell ausreizen.

Ein weiterer Performanceaspekt ist die Skalierbarkeit der serverseitigen Anwendung und deren Einfluss auf die Performance eines einzelnen Anwenders. Oft wird unterschätzt, wie erfolgreich eine App werden kann. Wenn statt 10 oder 100 plötzlich 10.000 Benutzer auf gemeinsame Services am Server zugreifen, dann kann das zu ungewollten Performanceproblemen oder auch zu Crashes führen und Requests laufen in Timeouts, die nicht korrekt behandelt werden. Mehr dazu im Abschnitt „Über den Tellerrand blicken: End-to-End-Testen“.

Entscheidend beim Testen von Performance ist es, den Ist-Zustand zu erheben. So besteht im Laufe der Weiterentwicklung die Möglichkeit, potenzielle Verbesserungen zu erkennen und die Auswirkung von Änderungen zu belegen. Dazu sollten Kennzahlen, die das mobile Endgerät betreffen, genauso wie serverseitige Kennzahlen berücksichtigt werden. Für mobile Anwendungen sind das Antwortzeit, übertragenes Datenvolumen, verbrauchter Speicher, Anzahl der Roundtrips zum Server sowie CPU- und Storage-Verbrauch am Gerät. Auf der Serverseite sind Werte wie Anzahl der Datenbankzugriffe, Webservice-Aufrufe, CPU- und Speicherverbrauch oder gespeichertes Datenvolumen in der Datenbank von Interesse.

Usability

Zum Thema Usability gibt es genug Literatur. Daher wird in diesem Artikel nicht vertieft darauf eingegangen. Ein enorm wichtiges Thema aber ist der Einfluss von Performance auf das Benutzerverhalten. Werden Usability-Tests durchgeführt, ist es relevant, die Anwendung auch dann zu testen, wenn man nicht der einzige Benutzer am System ist. Verschlechtern sich die Antwortzeiten des Servers, beeinträchtigt das auch die Usability. Friert beispielsweise die Anwendung ein, bis eine Antwort vom Server geliefert wird? Werden Usability-Tests auch auf unterschiedlichen Geräten durchgeführt und berücksichtigen sie alle Rahmenbedingungen?

Über den Tellerrand blicken: End-­to-­End-­Testen

Ein wichtiger Aspekt, der zu oft vergessen wird, ist, dass die Anwendung nicht nur auf dem mobilen Gerät alleine läuft. Sowohl bei Native- als auch bei Webanwendungen gibt es ständig Interaktionen mit den Servern, die Webinhalte oder andere benötigte Daten zur Verfügung stellen. Beim Testen sind daher sowohl die Kommunikation zum Server als auch die Verarbeitung der einzelnen Requests am Server und am Gerät zu testen. End-toEnd-Testen bedeutet, dass die Funktionalität, Performance und Skalierbarkeit vom Endgerät bis zur Datenbank analysiert werden muss.

Abbildung 1 zeigt einen sogenannten Transaction Flow, der den Login-Prozess einer mobilen Anwendung zeigt. Klickt der User in der mobilen Anwendung auf Login, wird ein Web-Request abgesetzt, der vom Webserver an den Application-Server weitergegeben wird. Die Anwendungslogik im Application-Server führt in Summe 212 Datenbankabfragen aus, um das Login abzuschließen.

212 Datenbankabfragen stellen zwar in der Testumgebung kein Problem dar – und vermutlich auch nicht, wenn 10 Benutzer versuchen, sich einzuloggen. Es wird aber zum Problem, sobald die Anwendung populär wird und sich tausende User gleichzeitig einloggen möchten. Spätestens dann ist es Zeit, sich die End-to-End-Performance genauer anzusehen und zu hinterfragen, warum ein einfaches Login derartig viele Ressourcen bindet.
Optimieren von Roundtrips

Es ist wichtig, sich anzusehen, wie viele Requests für die unterschiedlichen Funktionen der Anwendungen gegen den Server ausgeführt werden. Warum? Die Performance der Roundtrips hängt sehr stark von der aktuellen Verbindungsqualität und dem aktuellen Akkuzustand ab. Zusätzlich hat die Anzahl und Art der Roundtrips Einfluss auf die Akkulaufzeit und die Latenz. Vor allem bei nativen Anwendungen hat der Entwickler darauf zu achten, Roundtrips zu optimieren, um nicht ständig eine Datenverbindung offen zu halten oder ständig Datenverbindungen zu öffnen und zu schließen. Wo es aus Anwendungs- und Implementierungssicht möglich und sinnvoll ist, sollte man mehrere unabhängige Requests in wenige Requests bündeln. Das verbessert die Performance, da weniger Roundtrips benötigt werden und daher Latenz eine geringere Rolle spielt. Außerdem verlängert es die Akkulaufzeit.

Ein Beispiel zur Optimierung von Roundtrips ist eine Suchfunktion in der Anwendung: Anstatt für jedes eingegebene Zeichen einen Request an den Server zu schicken, ist es ratsamer, diese Roundtrips zu optimieren und erst dann Teilsuchergebnisse vom Server anzufordern, wenn der Benutzer mindestens 500 ms kein neues Zeichen eingegeben hat. Das reduziert die Roundtrips am Gerät sowie die Last am Server und hilft sicherzustellen, dass der Endanwender wirklich Resultate erhält und nicht in ein Timeout eines überlasteten Netzwerks oder Servers läuft. All dies verbessert somit die Performance und Usability.

Für das Testen und Optimieren von Roundtrips sind folgende Kennzahlen zu beachten, die aufzeigen, wie gut oder schlecht die Anwendung mit Roundtrips verfährt oder ob sie sich im Laufe der Entwicklung verbessern oder verschlechtern: Anzahl der dynamischen Requests, Datenvolumen, Anzahl der Images sowie der JavaScript- oder CSS-Dateien.

Optimieren der Server­Implementierung

Wie am Beispiel des Logins gezeigt ist es wichtig, die serverseitige Implementierung genauer unter die Lupe zu nehmen. Die Anzahl der Datenbankabfragen, WebserviceAufrufe, Log-Messages, Exceptions, aber auch die Ausführungszeit relevanter Funktionen sind weitere wichtige Kennzahlen, die während des Testens beachtet werden müssen. Werkzeuge für die serverseitige Performanceanalyse gibt es einige – abhängig von der verwendeten Technologie (Java, .NET, PHP, Ruby usw.). Optimal ist ein Werkzeug, das die gesamte End-to-End-Analyse bietet. Andernfalls ist es notwendig, manuell die Aktionen am Gerät mit jenen auf der Serverseite zu korrelieren.Weitere Informationen über serverseitige Optimierungen und Best Practices finden sich auf technologiespezifischen Performance-Blogs.

Die Rahmenbedingungen einbeziehen

Wie bereits erwähnt gibt es einige Faktoren, die Einfluss auf die Anwendung haben. Das Gerät und dessen Leistungsfähigkeit, die Version des Betriebssystems, der maximal zur Verfügung stehende Speicher, der Ladezustand der Batterie, die Anzahl der parallel laufenden Anwendungen oder die Verbindungsqualität zum Netzwerk – all diese Faktoren müssen berücksichtigt werden. Ein iPhone, das 15 Anwendungen im Hintergrund laufen lässt, nur noch auf 5 % Akkuleistung läuft und dabei eine schlechte Datenverbindung hat, wird sich anders verhalten als ein Testgerät, dass per USB ständig am Strom hängt, mit WiFi verbunden ist und lediglich die Anwendung ausführt, die getestet wird. Um wirklich aussagefähige Ergebnisse zu erhalten, ist es wichtig, diese Rahmenbedingungen beim Testen miteinzubeziehen.

Testen mit unterschiedlichen Geräten

Durch die ständig wachsende Anzahl der Endgeräte ist es nicht möglich, alle Geräte und OS-Versionen zum Testen verfügbar zu haben. Ratsam ist es aber, über eine gute Auswahl jener Geräte zu verfügen, die auch der typische Endanwender verwendet. Eine Marktanalyse zum aktuellen Anwenderverhalten dient hier als gute Vorlage. Neben der Beschaffung dieser Geräte besteht auch die Möglichkeit, diese als Remote-Service zuzukaufen. Es gibt diverse Anbieter, die „Gerätefarmen“ betreiben und verschiedenste Endgeräte für Testzwecke auf Stundenbasis vermieten. Testen mit unterschiedlichen Verbindungen

Ganz gleich, ob eigene Testgeräte oder Remote-Services verwendet werden – es ist darauf zu achten, dass diese Geräte nicht nur per Wi-Fi ans Netz angeschlossen sind, sondern die Möglichkeit haben, sich in unterschiedliche Netze der Netzbetreiber einzuwählen. Dies erlaubt das Testen von unterschiedlichen Verbindungstypen und auch das Testen, ob eine mobile Anwendung mit den Eigenheiten der Netzbetreiber umgehen kann. Bei Webinhalten wird das sognannte „Transcoding“ gern von Betreibern verwendet. Dabei werden gewisse Inhalte wie zum Beispiel JavaScript oder CSS auf deren Proxy-Servern voroptimiert und die Netzbetreiber greifen auf bewährte Techniken wie beispielsweise komprimieren, minimieren, Skript-Kommentare löschen, cachen von Inhalten zurück. Obwohl dies generell keine Probleme machen sollte, gibt es Fälle, in denen beispielsweise das Entfernen von Skript-Kommentaren dazu führt, dass Anwendungen nicht mehr richtig laufen, da diese Skript-Kommentare verwenden, um dynamisch JavaScript-Code nachzuladen. Werden diese Kommentare entfernt, dann landet dieser Code nicht mehr am Endgerät und führt zu Fehlern in der Anwendung.

Testen mit realistischer Hintergrundlast

Der typische Smartphone-Nutzer hat nicht nur eine Anwendung im Hintergrund laufen, sondern öffnet zwischen den gelegentlichen Reboots fünf, zehn, fünfzehn oder gar mehr Anwendungen und lässt diese im Hintergrund weiterlaufen. Diese Anwendungen verbrauchen neben Speicher auch CPU, Netzwerkbandbreite und Strom – alles Ressourcen, die der eigenen Anwendung fehlen. Daher ist es beim Testen ratsam, die Tests in realen Umgebungen auszuführen. Öffnen Sie doch Anwendungen wie Facebook, Twitter und Co. und lassen Sie diese im Hintergrund laufen. Stellen Sie sicher, dass Ihre Anwendung auch mit verringerter Leistung akzeptabel läuft.

Manuell und/oder automatisiert testen

Welche Möglichkeiten gibt es, um Tests tatsächlich auszuführen? Es bleibt natürlich nicht erspart, gewisse Aspekte der Anwendung manuell zu testen. Hier geht es vor allem um das Testen der Usability und um exploratives Testen. Genauso wie bei traditionellen Web- oder Rich-Client-Anwendungen ist es aber unumgänglich, Tests zu automatisieren. Automatisierung spart Zeit und stellt sicher, dass wichtige Tests der Anwendung immer gleich ausgeführt werden. Nur dadurch lassen sich fundierte Aussagen über die Qualität der Anwendung treffen und Verbesserungen objektiv nachweisen.

Manuelles Testen

Das Testen erfolgt im besten Fall auf dem tatsächlich genutzten Gerät, alternativ aber auch auf Emulatoren, die meistens gut genug sind, um die generelle Funktionalität der Anwendung zu testen. Für die Usability ist es aber definitiv ratsam, echte Endgeräte zu verwenden. Nur dadurch kann getestet werden, wie sich User-Interkation wie zum Beispiel Scrollen, Swipen oder Zoomen real anfühlen. Wie schon erwähnt kann man auch auf Remote-Device-Services zurückgreifen, da es oft nicht kostengünstig ist, alle unterschiedlichen Geräte anzuschaffen.

Automatisiertes Testen in der Continuous Integration

Automatisierung ermöglicht es einerseits, Zeit beim Ausführen der Tests zu sparen. Andererseits stellt es sicher, dass Testfälle immer gleich ausgeführt werden. Werden für diese Tests jene Kennzahlen ermittelt, die hier beschrieben wurden, wie zum Beispiel Antwortzeiten, Anzahl der Roundtrips, verbrauchte Bandbreite, verbrauchter Speicher oder Anzahl der Datenbankabfragen, so können diese Tests leicht dazu verwendet werden, sowohl funktionale als auch performancerelevante Regressionen zu entdecken. Erinnern wir uns an das Login, das 212 Datenbankabfragen benötigt: Testet man das Login mit einem automatisierten Test und werden Werkzeuge verwendet, welche die Anzahl der dabei ausgeführten Datenbankabfragen messen, dann findet man sehr leicht heraus, bei welchem Build und welcher Code-Änderung sich dieses Performance- oder Architekturproblem eingeschlichen hat. Abbildung 2 zeigt, wie durch ständige Überwachung wichtiger Kennzahlen Regressionen erkannt werden.

Testwerkzeuge

Testwerkzeuge und Frameworks sind für mobile Anwendungen noch nicht ganz so ausgereift wie für Desktop- und reine Webanwendungen. Nichtsdestotrotz finden sich einige Kandidaten, die sich vermehrter Beliebtheit erfreuen. Sei es Selenium für mobile Testframeworks, die von JavaScript-Framework-Herstellern angeboten werden, oder aber auch Mobile-Device-Testing-Services, die es erlauben, jegliche Art von User-Interkationen auf realen Geräten aufzuzeichnen und abzuspielen. Bei der Entscheidung des richtigen Testwerkzeuges kommt es stark auf die Art der Anwendung an. Möchte man trotz ständig ändernder Anwendung robuste Testskripte, dann ist es ratsam, ein Werkzeug auszuwählen, das eine flexible Skriptsprache anbietet. Schließlich soll vermieden werden, zu viel Zeit in die Wartung von Skripten zu stecken oder für jeden neuen Build viele Skripte neu aufzuzeichnen. Wenn es um Anwendungen mit einfacher User-Interaktion geht, dann reicht oft auch ein Werkzeug, das einfaches Record/Replay anbietet, ohne dahinter eine mächtige Sprache bereitzustellen.

Sollen die Tests automatisiert für jeden Build ausgeführt werden, ist vor allem darauf zu achten, ob sich das Werkzeug in den automatisierten Prozess einbinden lässt und wie effizient die Testausführung läuft. Wenn hunderte Tests bei jedem Build auszuführen sind, können die Ausführungszeit und der Overhead dieser Werkzeuge ausschlaggebend sein.

Es kann nicht alles getestet werden

Da es mit steigender Anzahl von Endgeräten und immer komplexeren Anwendungen meist nicht möglich ist, die gesamte Funktionalität auf allen Endgeräten zu testen, ist es meistens nicht zu vermeiden, dass gewisse Probleme erst vom Endanwender gefunden werden. Daher ist es wichtig, eine gute Strategie zu überlegen, wie man am besten an die Details dieser Probleme der Endanwender kommt. Das erlaubt es, diese Probleme so schnell wie möglich auszubessern und zu verhindern, dass zu viele weitere Anwender involviert werden.

Feedback­-Feature in Anwendung

Eine Möglichkeit ist es, in die Anwendung eine Feedback-Option einzubauen. Dem Anwender soll die Möglichkeit gegeben werden, an genau der Stelle, wo ein Problem aufgetaucht ist, dieses Problem zu melden. Am besten so implementiert, dass – neben dem aktuellen Status in der Anwendung – auch gleich Umgebungsvariablen wie CPU, Batterie und die Anzahl der Anwendungen mitprotokolliert werden. Kommt es dann zu einem Crash, sollte der Benutzer beim nächsten Start der Anwendung die Möglichkeit erhalten, diesen Crashreport zu schicken.

Automatische Fehlererkennung im Echtbetrieb

Wie bereits für reguläre Webanwendungen Usus gibt es auch bei mobilen Anwendungen (Web oder Native) die Option des Real-UserMonitoring. Hierbei handelt es sich darum, alle wichtigen Daten während der Benutzung der Anwendung aufzuzeichnen und diese zu definierten Zeitpunkten an den eigenen Server zu schicken. Diese Daten beinhalten zum Beispiel: wichtige und fehlgeschlagene UserInterkationen, die ausgeführten Funktionen der Anwendung, die Dauer dieser Aktionen, die angeforderten Daten vom Server, die wichtigsten Umgebungsvariablen und auch Crashreports oder JavaScript-Fehler. Werden diese Daten analysiert, so erhält man ein genaues Bild davon, welche Benutzer (iPhone, iOS usw.) in welche Probleme mit der Anwendung laufen (Crashes bei gewissen Aktionen, fehlerhafter JavaScript-Code, langsame Performance bei wichtigen Features usw.). Kommt es zu einem Performanceproblem oder gar zu einem Crash, liegen alle notwendigen Informationen vor, die zur Rekonstruktion eines Anwenderproblems benötigt werden. Abbildung 3 zeigt genau die Aktionen eines Benutzers, bis dieser bei der Upload-Funktion der Anwendung in einen Fehler gelaufen ist.

Fazit

Testen von mobilen Anwendungen – ganz gleich ob Web, Native oder Hybrid – ist unumgänglich. Anwendungen mit Bugs oder Performanceproblemen werden von den Anwendern sofort durch schlechte Bewertung abgestraft. Wichtig ist es, auf Bugs, Crashes, Performance und Usability zu testen, denn diese Faktoren sind maßgeblich für den Erfolg einer Anwendung. Manuelles Testen ist notwendig, aber erst automatisiertes Testen und das automatisierte Analysieren von wichtigen Kennzahlen ermöglicht es, bessere und stabilere Anwendungen zu entwickeln, die beim Upload in den App Store bessere Chancen haben, erfolgreich zu werden. Da leider nicht immer alles getestet werden kann, ist es wichtig eine Monitoring-Strategie zu verfolgen, welche die Perspektive der Endanwender einbezieht. Werkzeuge, die dies alles unterstützen, gibt es bereits und sie werden ständig verbessert.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Kategorien

Recent Posts