Wenn Sie ein Element oder ein System von Elementen testen, geschieht dies isoliert. Wenn Sie beispielsweise ein ViewModel testen möchten, müssen Sie keinen Emulator starten und keine Benutzeroberfläche öffnen, da es nicht vom Android-Framework abhängt (oder abhängen sollte).
Das Testobjekt ist jedoch möglicherweise von anderen abhängig, damit es funktioniert. Ein ViewModel kann beispielsweise von einem Datenrepository abhängen.
Wenn Sie eine Abhängigkeit für ein Testobjekt bereitstellen müssen, ist es üblich, einen Test-Double (oder ein Testobjekt) zu erstellen. Test Doubles sind Objekte, die wie Komponenten in Ihrer App aussehen und sich so verhalten, werden aber in Ihrem Test erstellt, um ein bestimmtes Verhalten oder Daten bereitzustellen. Die Hauptvorteile sind, dass sie Ihre Tests schneller und einfacher machen.
Arten von Test-Doubles
Es gibt verschiedene Arten von Test-Doubles:
Fake | Ein Test-Double mit einer „funktionierenden“ Implementierung der Klasse, die jedoch so implementiert ist, dass sie für Tests geeignet, aber für die Produktion ungeeignet ist.
Beispiel: eine In-Memory-Datenbank. Für Fakes ist kein Mocking-Framework erforderlich und sie sind effizient. Sie sind bevorzugt. |
---|---|
Mock | Ein Test-Double, das sich wie programmiert verhält und für das bestimmte Interaktionen erwartet werden. Mocks schlagen bei Tests fehl, wenn ihre Interaktionen nicht den von Ihnen definierten Anforderungen entsprechen. Mocks werden in der Regel mit einem Mocking-Framework erstellt, um all dies zu erreichen.
Beispiel: Prüfen, ob eine Methode in einer Datenbank genau einmal aufgerufen wurde. |
Stub | Ein Test-Double, das sich wie programmiert verhält, aber keine Erwartungen an seine Interaktionen hat. Werden in der Regel mit einem Mocking-Framework erstellt. Aus Gründen der Einfachheit werden Fakes Stubs vorgezogen. |
Dummy | Ein Test-Double, das übergeben, aber nicht verwendet wird, z. B. wenn Sie es nur als Parameter angeben müssen.
Beispiel: Eine leere Funktion, die als Klick-Callback übergeben wird. |
Spy – Susan Cooper Undercover | Ein Wrapper für ein echtes Objekt, der ähnlich wie Mockups auch einige zusätzliche Informationen erfasst. Sie werden in der Regel vermieden, da sie die Komplexität erhöhen. Daher werden Fakes oder Mockups Spionen vorgezogen. |
Schatten | In Robolectric verwendete Fälschung. |
Beispiel für die Verwendung eines gefälschten Dokuments
Angenommen, Sie möchten ein ViewModel, das von einer Schnittstelle namens UserRepository
abhängt, und den Namen des ersten Nutzers einer Benutzeroberfläche zur Verfügung stellen. Sie können einen gefälschten Test-Double erstellen, indem Sie die Benutzeroberfläche implementieren und bekannte Daten zurückgeben.
object FakeUserRepository : UserRepository {
fun getUsers() = listOf(UserAlice, UserBob)
}
val const UserAlice = User("Alice")
val const UserBob = User("Bob")
Diese gefälschte UserRepository
muss nicht von den lokalen und Remote-Datenquellen abhängen, die in der Produktionsversion verwendet werden. Die Datei befindet sich im Test-Quellsatz und wird nicht mit der Produktions-App ausgeliefert.
Im folgenden Test wird überprüft, ob das ViewModel den ersten Nutzernamen korrekt der Ansicht zur Verfügung stellt.
@Test
fun viewModelA_loadsUsers_showsFirstUser() {
// Given a VM using fake data
val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init
// Verify that the exposed data is correct
assertEquals(viewModel.firstUserName, UserAlice.name)
}
Das Ersetzen der UserRepository
durch eine Fälschung ist in einem Unit-Test ganz einfach, da das ViewModel vom Tester erstellt wird. Bei größeren Tests kann es jedoch schwierig sein, beliebige Elemente zu ersetzen.
Komponenten ersetzen und Abhängigkeits-Injection
Wenn bei Tests die Erstellung der zu testenden Systeme nicht gesteuert werden kann, wird das Ersetzen von Komponenten durch Testdoppel schwieriger. Außerdem muss die Architektur Ihrer App einem testbaren Design folgen.
Selbst große End-to-End-Tests können von Testdoppeln profitieren, z. B. ein instrumentierter UI-Test, der einen vollständigen Nutzerfluss in Ihrer App durchläuft. In diesem Fall sollten Sie Ihren Test hermetisch gestalten. Bei einem hermetischen Test werden alle externen Abhängigkeiten vermieden, z. B. das Abrufen von Daten aus dem Internet. Dies verbessert Zuverlässigkeit und Leistung.
Sie können Ihre App so entwerfen, dass diese Flexibilität manuell erreicht wird. Wir empfehlen jedoch, ein Dependency Injection-Framework wie Hilt zu verwenden, um Komponenten in Ihrer App zum Testzeitpunkt zu ersetzen. Weitere Informationen finden Sie im Hilt-Testleitfaden.
Nächste Schritte
Auf der Seite Teststrategien erfahren Sie, wie Sie mit verschiedenen Arten von Tests Ihre Produktivität steigern können.