Principes de base des tests des applications Android

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 chaque erreur utilisateur ou de parcourir chaque flux utilisateur.

Toutefois, les tests manuels sont difficilement évolutifs et il est facile de passer à côté des régressions dans le comportement de votre application. Les tests automatisés consistent à utiliser des outils qui effectuent des tests pour vous. 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 du sujet :

  • Tests fonctionnels : mon application fait-elle ce qu'elle est censée faire ?
  • Tests de performances : le fait-il rapidement et efficacement ?
  • Tests d'accessibilité : l'application fonctionne-t-elle bien avec les services d'accessibilité ?
  • Tests de compatibilité : l'application 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 tests volumineux permettent de valider simultanément de plus grandes parties de l'application, 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.
Les tests peuvent être petits, moyens ou grands.
Figure 1 : Étendues de test dans une application typique.

Il existe de nombreuses façons de classer les tests. Toutefois, la distinction la plus importante pour les développeurs d'applications concerne l'emplacement d'exécution des tests.

Tests instrumentés et tests locaux

Vous pouvez exécuter des tests sur un appareil Android ou sur un autre ordinateur :

  • Les tests instrumentés s'exécutent sur un appareil Android, physique ou émulé. L'application est créée et installée en même temps qu'une application de test qui injecte des commandes et lit l'état. Les tests instrumentés sont généralement des tests d'UI qui lancent une application et interagissent ensuite avec elle.
  • Les tests locaux s'exécutent sur votre machine 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.
Les tests peuvent s'exécuter en tant que tests instrumentés sur un appareil ou en tant que tests locaux sur votre machine de développement.
Figure 2 : Différents types de tests en fonction de l'endroit où ils sont exécutés.

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 :

  • Test local de grande taille : vous pouvez utiliser un simulateur Android qui s'exécute localement, comme Robolectric.
  • Petit test instrumenté : vous pouvez vérifier que votre code fonctionne correctement avec une fonctionnalité du 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 celui-ci de manière isolée. Les architectures testables présentent d'autres avantages, comme une meilleure lisibilité, maintenabilité, évolutivité et réutilisabilité.

Une architecture non testable produit les éléments suivants :

  • Des tests plus volumineux, plus lents et plus irréguliers. Les classes qui ne peuvent pas être testées de manière unitaire peuvent devoir être couvertes par des tests d'intégration ou d'interface utilisateur plus importants.
  • Moins d'opportunités de tester différents scénarios. Les tests plus importants 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 de l'architecture des applications.

Approches de 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 la 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 métier et d'UI ailleurs, par exemple vers un composable, un ViewModel ou une couche de domaine.
  • Évitez les dépendances de framework directes dans les classes contenant une 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 que vous connaissez 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.