Mit automatisierten Tests können Sie die App-Qualität auf verschiedene Weise verbessern. So können Sie beispielsweise Validierungen durchführen, Regressionen erkennen und die Kompatibilität prüfen. Mit einer guten Teststrategie können Sie automatisierte Tests nutzen, um sich auf einen wichtigen Vorteil zu konzentrieren: die Produktivität der Entwickler.
Teams erzielen eine höhere Produktivität, wenn sie einen systematischen Testansatz mit Infrastrukturverbesserungen kombinieren. So erhalten Sie zeitnahes Feedback zum Verhalten des Codes. Eine gute Teststrategie erfüllt folgende Kriterien:
- Probleme werden so früh wie möglich erkannt.
- Sie werden schnell ausgeführt.
- Sie gibt klare Hinweise, wenn etwas behoben werden muss.
Auf dieser Seite erfahren Sie, welche Arten von Tests Sie implementieren, wo Sie sie ausführen und wie oft.
Die Testpyramide
In modernen Anwendungen können Sie Tests nach Größe kategorisieren. Kleine Tests konzentrieren sich nur auf einen kleinen Teil des Codes und sind daher schnell und zuverlässig. Große Tests haben einen großen Umfang und erfordern komplexere Konfigurationen, die sich nur schwer verwalten lassen. Große Tests sind jedoch repräsentativer* und können auf einmal viel mehr Probleme aufdecken.
*Fidelity bezieht sich auf die Ähnlichkeit der Testlaufzeitumgebung mit der Produktionsumgebung.
Die meisten Apps sollten viele kleine und relativ wenige große Tests durchführen. Die Verteilung der Tests in jeder Kategorie sollte eine Pyramide bilden, wobei die Zahl der kleinen Tests die Basis und die weniger großen Tests die Basis bilden.
Kosten eines Bugs minimieren
Mit einer guten Teststrategie maximieren Sie die Produktivität der Entwickler und minimieren gleichzeitig die Kosten der Fehlersuche.
Sehen wir uns ein Beispiel für eine möglicherweise ineffiziente Strategie an. Hier wird die Anzahl der Tests nach Größe nicht zu einer Pyramide organisiert. Es gibt zu viele große End-to-End-Tests und zu wenige UI-Tests für Komponenten:
Das bedeutet, dass vor dem Zusammenführen zu wenige Tests ausgeführt werden. Wenn ein Fehler auftritt, wird er möglicherweise erst bei den täglichen oder wöchentlichen End-to-End-Tests erkannt.
Es ist wichtig zu berücksichtigen, welche Auswirkungen dies auf die Kosten für die Identifizierung und Behebung von Fehlern hat und warum es wichtig ist, Ihre Testbemühungen auf kleinere und häufigere Tests zu konzentrieren:
- Wenn der Fehler von einem Einheitentest erkannt wird, wird er normalerweise innerhalb weniger Minuten behoben, sodass die Kosten niedrig sind.
- Bei einem End-to-End-Test kann es Tage dauern, bis derselbe Fehler gefunden wird. Dies könnte mehrere Teammitglieder in Anspruch nehmen, was die Produktivität insgesamt verringert und eine Veröffentlichung möglicherweise verzögert. Die Kosten für diesen Fehler sind höher.
Eine ineffiziente Teststrategie ist jedoch besser als gar keine Strategie. Wenn ein Fehler in die Produktion gelangt, dauert es oft Wochen, bis die Fehlerbehebung auf den Geräten der Nutzer verfügbar ist. Daher ist die Feedbackschleife die längste und teuerste.
Eine skalierbare Teststrategie
Die Testpyramide wurde traditionell in drei Kategorien unterteilt:
- Einheitentests
- Integrationstests
- End-to-End-Tests
Diese Konzepte haben jedoch keine genauen Definitionen. Daher können Teams ihre Kategorien auch anders definieren, z. B. mit fünf Ebenen:
- Ein Einheitstest wird auf dem Hostcomputer ausgeführt und prüft eine einzelne funktionale Logikeinheit ohne Abhängigkeiten vom Android-Framework.
- Beispiel: Überprüfung von Abweichungen um eins bei einer mathematischen Funktion
- Bei einem Komponententest wird die Funktionalität oder das Erscheinungsbild eines Moduls oder einer Komponente unabhängig von anderen Komponenten im System überprüft. Im Gegensatz zu Unit-Tests erstreckt sich der Bereich eines Komponententests auf höhere Abstraktionsebenen über einzelne Methoden und Klassen hinaus.
- Beispiel: Screenshot-Test für eine benutzerdefinierte Schaltfläche
- Bei einem Funktionstest wird die Interaktion von zwei oder mehr unabhängigen Komponenten oder Modulen überprüft. Funktionstests sind größer und komplexer und werden in der Regel auf Funktionsebene durchgeführt.
- Beispiel: UI-Verhaltenstests, mit denen die Statusverwaltung auf einem Bildschirm überprüft wird
- Bei einem Anwendungstest wird die Funktionalität der gesamten Anwendung in Form eines ausführbaren Binärprogramms überprüft. Das sind umfangreiche Integrationstests, bei denen ein debuggbarer Binärcode als Testsystem verwendet wird, z. B. ein Dev-Build, das Test-Hooks enthalten kann.
- Beispiel: UI-Verhaltenstest zur Überprüfung von Konfigurationsänderungen in einem faltbaren Gerät, Lokalisierungs- und Bedienungshilfentests
- Mit einem Release-Kandidatentest wird die Funktionalität eines Release-Builds überprüft.
Sie ähneln Anwendungstests, mit der Ausnahme, dass das Binärprogramm minimiert und optimiert wird. Das sind umfangreiche End-to-End-Integrationstests, die in einer Umgebung ausgeführt werden, die der Produktionsumgebung so nahe wie möglich kommt, ohne dass die App öffentlichen Nutzerkonten oder öffentlichen Backends ausgesetzt wird.
- Beispiel: Kritische User Journeys, Leistungstests
Bei dieser Kategorisierung werden die Treue, die Zeit, der Umfang und die Isolationsstufe berücksichtigt. Sie können verschiedene Arten von Tests auf mehreren Ebenen durchführen. Die Anwendungstestebene kann beispielsweise Verhaltens-, Screenshot- und Leistungstests enthalten.
Aufgabenstellung |
Netzwerkzugriff |
Umsetzung |
Build-Typ |
Lebenszyklus |
|
---|---|---|---|---|---|
Einheit |
Einzelne Methode oder Klasse mit minimalen Abhängigkeiten. |
Nein |
Lokal |
Debug-fähig |
Vor dem Zusammenführen |
Komponente |
Modul- oder Komponentenebene Mehrere Kurse gleichzeitig |
Nein |
Lokal |
Debugfähig |
Vor Zusammenführung |
Funktion |
Funktionsebene Integration in Komponenten anderer Teams |
Gemockt |
Lokal |
Debugfähig |
Vor dem Zusammenführen |
Anwendung |
Anwendungsebene Einbindung in Funktionen und/oder Dienste anderer Teams |
Gemockter |
Emulator |
Debugfähig |
Vor der Zusammenführung |
Release-Kandidat |
Anwendungsebene Einbindung in Funktionen und/oder Dienste anderer Teams |
Prod-Server |
Emulator |
Minimierter Release-Build |
Nach der Zusammenführung |
Testkategorie festlegen
Als Faustregel sollten Sie die unterste Schicht der Pyramide in Betracht ziehen, die dem Team das richtige Maß an Feedback geben kann.
Überlegen Sie zum Beispiel, wie Sie die Implementierung dieser Funktion testen können: die Benutzeroberfläche eines Anmeldevorgangs. Je nachdem, was Sie testen möchten, wählen Sie eine der folgenden Kategorien aus:
Testobjekt |
Beschreibung dessen, was getestet wird |
Testkategorie |
Beispiel für einen Testtyp |
---|---|---|---|
Logik der Formularvalidierung |
Eine Klasse, die die E-Mail-Adresse anhand eines regulären Ausdrucks validiert und prüft, ob das Passwortfeld eingegeben wurde. Es hat keine Abhängigkeiten. |
Einheitentests |
|
Verhalten der Benutzeroberfläche für das Anmeldeformular |
Ein Formular mit einer Schaltfläche, die nur aktiviert wird, wenn das Formular validiert wurde |
Komponententests |
UI-Verhaltenstest, der mit Robolectric ausgeführt wird |
Benutzeroberfläche des Anmeldeformulars |
Ein Formular, das einer UX-Spezifikation folgt |
Komponententests |
|
Integration mit dem Authentifizierungsmanager |
Die Benutzeroberfläche, die Anmeldedaten an einen Authentifizierungsmanager sendet und Antworten empfängt, die verschiedene Fehler enthalten können. |
Funktionstests |
|
Anmeldedialogfeld |
Ein Bildschirm, auf dem das Anmeldeformular zu sehen ist, wenn die Anmeldeschaltfläche gedrückt wird. |
Anwendungstests |
UI-Verhaltenstest, der mit Robolectric ausgeführt wird |
Wichtige User Journey: Anmeldung |
Ein vollständiger Anmeldevorgang mit einem Testkonto auf einem Staging-Server |
Release Candidate |
End-to-End-Compose UI-Verhaltenstest, der auf dem Gerät ausgeführt wird |
In einigen Fällen ist es subjektiv, ob etwas zu einer bestimmten Kategorie gehört. Es kann weitere Gründe geben, warum ein Test nach oben oder unten verschoben wird, z. B. Infrastrukturkosten, Instabilität und lange Testzeiten.
Die Testkategorie bestimmt nicht den Testtyp und nicht alle Funktionen müssen in jeder Kategorie getestet werden.
Manuelle Tests können auch Teil Ihrer Teststrategie sein. Üblicherweise führen QA-Teams Releasekandidatentests durch, können aber auch an anderen Phasen beteiligt sein. Zum Beispiel exploratives Testen auf Fehler in einer Funktion ohne Skript.
Testinfrastruktur
Eine Teststrategie muss von der Infrastruktur und den Tools unterstützt werden, damit Entwickler ihre Tests kontinuierlich ausführen und Regeln durchsetzen können, die das Bestehen aller Tests garantieren.
Sie können Tests nach Umfang kategorisieren, um zu definieren, wann und wo welche Tests ausgeführt werden. Hier ein Beispiel für das 5-Schichten-Modell:
Kategorie |
Umgebung (wo) |
Trigger (wenn) |
---|---|---|
Einheit |
[Local][4] |
Bei jedem Commit |
Komponente |
Lokal |
Bei jedem Commit |
Funktion |
Lokal und Emulatoren |
Vor dem Zusammenführen, bevor eine Änderung zusammengeführt oder eingereicht wird |
Anwendung |
Lokal, Emulatoren, 1 Smartphone, 1 faltbares Smartphone |
Nach dem Zusammenführen, nachdem eine Zusammenführung oder Änderung eingereicht wurde |
Releasekandidaten |
8 verschiedene Smartphones, 1 faltbares Smartphone, 1 Tablet |
Vor Veröffentlichung |
- Unit- und Komponententests werden für jeden neuen Commit im Continuous-Integration-System ausgeführt, jedoch nur für die betroffenen Module.
- Alle Einheits-, Komponenten- und Funktionstests werden ausgeführt, bevor eine Änderung zusammengeführt oder eingereicht wird.
- Anwendungstests werden nach dem Zusammenführen ausgeführt.
- Release Candidate-Tests werden jede Nacht auf Smartphones, faltbaren Geräten und Tablets durchgeführt.
- Vor einem Release werden Releasekandidaten-Tests auf einer großen Anzahl von Geräten ausgeführt.
Diese Regeln können sich im Laufe der Zeit ändern, wenn sich die Anzahl der Tests auf die Produktivität auswirkt. Wenn Sie beispielsweise die Tests auf eine nächtliche Taktung umstellen, können Sie die CI-Build- und Testzeiten verkürzen, aber auch die Feedbackschleife verlängern.