Lorsque vous testez un élément ou un système d'éléments, vous le faites de manière isolé. Par exemple, pour tester un ViewModel, vous n'avez pas besoin de démarrer un émulateur et de lancer une UI, car il ne dépend pas (ou ne devrait pas) du framework Android.
Toutefois, l'objet testé peut dépendre d'autres éléments pour fonctionner. Par exemple, un ViewModel peut dépendre d'un dépôt de données pour fonctionner.
Lorsque vous devez fournir une dépendance à un sujet testé, il est courant de créer un double de test (ou un objet de test). Les doubles de test sont des objets qui ressemblent à des composants de votre application et qui se comportent comme tels, mais ils sont créés dans votre test pour fournir un comportement ou des données spécifiques. Les principaux avantages sont qu'ils rendent vos tests plus rapides et plus simples.
Types de doubles de test
Il existe différents types de doublons de test:
Falsifié | Double de test qui dispose d'une implémentation "fonctionnelle" de la classe, mais qui est implémenté de manière à être adapté aux tests, mais non à la production.
Exemple: une base de données en mémoire. Les faux ne nécessitent pas de framework de simulation et sont légers. Il est recommandé de les utiliser. |
---|---|
Mock | Double de test qui se comporte comme vous le programmez et qui a des attentes concernant ses interactions. Les tests échouent si leurs interactions ne correspondent pas aux exigences que vous définissez. Pour ce faire, les simulations sont généralement créées avec un framework de simulation.
Exemple: Vérifier qu'une méthode d'une base de données a été appelée exactement une fois. |
Stub | Double de test qui se comporte comme vous le programmez, mais qui n'a pas d'attentes concernant ses interactions. Elles sont généralement créées avec un framework de simulation. Pour des raisons de simplicité, il est préférable d'utiliser des faux plutôt que des bouchons. |
Factice | Double de test transmis, mais non utilisé, par exemple si vous devez simplement le fournir en tant que paramètre.
Exemple: fonction vide transmise en tant que rappel de clic. |
Espionnage | Wrapper sur un objet réel qui suit également certaines informations supplémentaires, comme les mocks. Elles sont généralement évitées, car elles ajoutent de la complexité. Les faux ou les simulations sont donc à privilégier aux espions. |
Ombre | Faux utilisé dans Robolectric. |
Exemple d'utilisation d'un faux
Supposons que vous souhaitiez effectuer un test unitaire d'un ViewModel qui dépend d'une interface appelée UserRepository
et qui expose le nom du premier utilisateur à une UI. Vous pouvez créer un double de test factice en implémentant l'interface et en renvoyant des données connues.
object FakeUserRepository : UserRepository {
fun getUsers() = listOf(UserAlice, UserBob)
}
val const UserAlice = User("Alice")
val const UserBob = User("Bob")
Ce faux UserRepository
n'a pas besoin de dépendre des sources de données locales et distantes que la version de production utiliserait. Le fichier se trouve dans l'ensemble de sources de test et n'est pas fourni avec l'application de production.
Le test suivant vérifie que le ViewModel expose correctement le premier nom d'utilisateur à la vue.
@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)
}
Remplacer le UserRepository
par un faux est facile dans un test unitaire, car le ViewModel est créé par le testeur. Toutefois, il peut être difficile de remplacer des éléments arbitraires dans des tests plus importants.
Remplacement de composants et injection de dépendances
Lorsque les tests n'ont aucun contrôle sur la création des systèmes testés, le remplacement des composants par des doubles de test devient plus complexe et nécessite que l'architecture de votre application suive une conception testable.
Même les grands tests de bout en bout peuvent bénéficier de l'utilisation de doubles de test, comme un test d'interface utilisateur instrumenté qui parcourt un parcours utilisateur complet dans votre application. Dans ce cas, vous pouvez rendre votre test hermétique. Un test hermétique évite toutes les dépendances externes, telles que l'extraction de données sur Internet. Cela améliore la fiabilité et les performances.
Vous pouvez concevoir votre application pour obtenir cette flexibilité manuellement, mais nous vous recommandons d'utiliser un framework d'injection de dépendances tel que Hilt pour remplacer les composants de votre application au moment des tests. Consultez le guide des tests avec Hilt.
Étapes suivantes
La page Stratégies de test explique comment améliorer votre productivité à l'aide de différents types de tests.