Cette page présente les principes fondamentaux des tests d'applications Android, y compris les bonnes pratiques centrales et leurs avantages.
Avantages des tests
Les tests s'inscrivent dans le processus de développement d'une application. En effectuant régulièrement des tests sur votre application, vous pouvez vérifier son adéquation, son comportement et son utilisation avant de la mettre à disposition de tous.
Vous pouvez tester votre application manuellement en y naviguant. Vous pouvez utiliser différents appareils et émulateurs, modifier la langue du système et essayer de générer toutes les erreurs utilisateur ou de parcourir tous les flux utilisateur.
Cependant, les tests manuels sont difficiles à mettre à l'échelle et il peut être facile de négliger les régressions dans le comportement de votre application. Les tests automatisés impliquent l'utilisation d'outils qui effectuent des tests à votre place. Ils sont plus rapides, plus reproductibles et vous fournissent généralement des commentaires plus exploitables sur votre application plus tôt dans le processus de développement.
Types de tests dans Android
Les applications mobiles sont complexes et doivent fonctionner correctement dans de nombreux environnements. Il existe donc de nombreux types de tests.
Objet
Par exemple, il existe différents types de tests en fonction de l'objet :
- Tests fonctionnels : mon application fait-elle ce qu'elle est censée faire ?
- Tests de performances : le fait-elle rapidement et efficacement ?
- Tests d'accessibilité : fonctionne-t-elle correctement avec les services d'accessibilité ?
- Tests de compatibilité : fonctionne-t-elle correctement sur tous les appareils et niveaux d'API ?
Champ d'application
Les tests varient également en fonction de la taille ou du degré d'isolation :
- Les tests unitaires ou petits tests ne vérifient qu'une très petite partie de l'application, comme une méthode ou une classe.
- Les tests de bout en bout ou grands tests vérifient des parties plus importantes de l'application en même temps, comme un écran entier ou un flux utilisateur.
- Les tests moyens se situent entre les deux et vérifient l'intégration entre deux unités ou plus.
Il existe de nombreuses façons de classer les tests. Cependant, la distinction la plus importante pour les développeurs d'applications est l'endroit où les tests sont exécutés.
Tests d'instrumentation et tests locaux
Vous pouvez exécuter des tests sur un appareil Android ou sur un autre ordinateur :
- Les tests d'instrumentation s'exécutent sur un appareil Android, physique ou émulé. L'application est compilée et installée avec une application de test qui injecte des commandes et lit l'état. Les tests d'instrumentation sont généralement des tests d'UI qui lancent une application, puis interagissent avec elle.
- Les tests locaux s'exécutent sur votre ordinateur de développement ou sur un serveur. Ils sont donc également appelés tests côté hôte. Ils sont généralement petits et rapides, et isolent le sujet testé du reste de l'application.
Tous les tests unitaires ne sont pas locaux, et tous les tests de bout en bout ne s'exécutent pas sur un appareil. Exemple :
- Grand test local : vous pouvez utiliser un simulateur Android qui s'exécute localement, tel que Robolectric.
- Petit test d'instrumentation : vous pouvez vérifier que votre code fonctionne correctement avec une fonctionnalité de framework, telle qu'une base de données SQLite. Vous pouvez exécuter ce test sur plusieurs appareils pour vérifier l'intégration avec plusieurs versions de SQLite.
Exemples
Les extraits suivants montrent comment interagir avec l'UI dans un test d'UI instrumenté qui clique sur un élément et vérifie qu'un autre élément s'affiche.
Espresso
// When the Continue button is clicked
onView(withText("Continue"))
.perform(click())
// Then the Welcome screen is displayed
onView(withText("Welcome"))
.check(matches(isDisplayed()))
Compose UI
// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()
// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
Cet extrait montre une partie d'un test unitaire pour un ViewModel (test local côté hôte) :
// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)
// When data is loaded
viewModel.loadData()
// Then it should be exposing data
assertTrue(viewModel.data != null)
Architecture testable
Avec une architecture d'application testable, le code suit une structure qui vous permet de tester facilement différentes parties de manière isolée. Les architectures testables présentent d'autres avantages, tels qu'une meilleure lisibilité, une meilleure maintenabilité, une meilleure évolutivité et une meilleure réutilisabilité.
Une architecture non testable produit les éléments suivants :
- Des tests plus volumineux, plus lents et plus instables. Les classes qui ne peuvent pas être testées de manière unitaire peuvent devoir être couvertes par des tests d'intégration ou des tests d'UI plus volumineux.
- Moins de possibilités de tester différents scénarios. Les tests plus volumineux sont plus lents. Il peut donc être irréaliste de tester tous les états possibles d'une application.
Pour en savoir plus sur les consignes d'architecture, consultez le guide sur l'architecture des applications.
Approches du découplage
Si vous pouvez extraire une partie d'une fonction, d'une classe ou d'un module du reste, il est plus facile et plus efficace de le tester. Cette pratique est appelée découplage. Il s'agit du concept le plus important pour une architecture testable.
Voici quelques techniques de découplage courantes :
- Divisez une application en couches telles que la présentation, le domaine et les données. Vous pouvez également diviser une application en modules, un par fonctionnalité.
- Évitez d'ajouter de la logique aux entités qui ont de grandes dépendances, telles que les activités et les fragments. Utilisez ces classes comme points d'entrée du framework et déplacez la logique d'UI et la logique métier ailleurs, par exemple vers une couche Composable, ViewModel ou de domaine.
- Évitez les dépendances de framework directes dans les classes contenant la logique métier. Par exemple, n'utilisez pas de contextes Android dans les ViewModels.
- Facilitez le remplacement des dépendances. Par exemple, utilisez des interfaces au lieu d'implémentations concrètes. Utilisez l'injection de dépendances même si vous n'utilisez pas de framework d'injection de dépendances.
Étapes suivantes
Maintenant que vous savez pourquoi vous devez effectuer des tests et quels sont les deux principaux types de tests, vous pouvez lire Éléments à tester ou en savoir plus sur les Stratégies de test
Si vous préférez créer votre premier test et apprendre par la pratique, consultez les ateliers de programmation sur les tests.