Ressources inactives d'Espresso

Une ressource inactive représente une opération asynchrone dont les résultats affectent les opérations ultérieures d'un test d'interface utilisateur. En enregistrant des ressources inactives avec Espresso, vous pouvez valider ces opérations asynchrones de manière plus fiable lorsque vous testez votre application.

Identifier les cas où des ressources inactives sont nécessaires

Espresso fournit un ensemble sophistiqué de fonctionnalités de synchronisation. Cependant, cette caractéristique du framework ne s'applique qu'aux opérations qui publient des messages sur MessageQueue, comme une sous-classe de View qui dessine son contenu à l'écran.

Comme Espresso n'a connaissance d'aucune autre opération asynchrone, y compris de celles qui s'exécutent sur un thread en arrière-plan, il ne peut pas fournir de garanties de synchronisation dans ces situations. Pour que Espresso soit informé des opérations de longue durée de votre application, vous devez enregistrer chacune d'elles en tant que ressource inactive.

Si vous n'utilisez pas de ressources d'inactivité lorsque vous testez les résultats des tâches asynchrones de votre application, vous devrez peut-être utiliser l'une des solutions de contournement incorrectes suivantes pour améliorer la fiabilité de vos tests:

  • Ajouter des appels à Thread.sleep() Lorsque vous ajoutez des retards artificiels à vos tests, l'exécution de votre suite de tests prend plus de temps, et vos tests peuvent toujours échouer s'ils sont exécutés sur des appareils plus lents. En outre, ces délais ne s'adaptent pas bien, car votre application devra peut-être effectuer un travail asynchrone plus chronophage dans une prochaine version.
  • Implémenter des wrappers de nouvelle tentative,qui utilisent une boucle pour vérifier à plusieurs reprises si votre application effectue toujours un travail asynchrone jusqu'à l'expiration d'un délai. Même si vous spécifiez un nombre maximal de nouvelles tentatives dans vos tests, chaque réexécution consomme des ressources système, en particulier le processeur.
  • Utiliser des instances de CountDownLatch,qui permettent à un ou plusieurs threads d'attendre qu'un nombre spécifique d'opérations en cours d'exécution dans un autre thread soit terminé. Ces objets nécessitent que vous spécifiiez un délai avant expiration. Sinon, votre application risque d'être bloquée indéfiniment. Ces loquets ajoutent également de la complexité inutile à votre code, ce qui complique la maintenance.

Espresso vous permet de supprimer ces solutions de contournement non fiables de vos tests et d'enregistrer le travail asynchrone de votre application en tant que ressources d'inactivité.

Cas d'utilisation courants

Lorsque vous effectuez des opérations semblables aux exemples suivants dans vos tests, envisagez d'utiliser une ressource d'inactivité:

  • Chargement de données à partir d'Internet ou d'une source de données locale
  • Établir des connexions avec des bases de données et des rappels.
  • Gérer les services, à l'aide d'un service système ou d'une instance de IntentService.
  • Exécution d'une logique métier complexe, telle que des transformations bitmap

Il est particulièrement important d'enregistrer les ressources inactives lorsque ces opérations mettent à jour une interface utilisateur que vos tests valident par la suite.

Exemples d'implémentations de ressources d'inactivité

La liste suivante décrit plusieurs exemples d'implémentations de ressources inactives que vous pouvez intégrer à votre application:

CountingIdlingResource
Gère un compteur de tâches actives. Lorsque le compteur est égal à zéro, la ressource associée est considérée comme inactive. Cette fonctionnalité ressemble beaucoup à celle d'un Semaphore. Dans la plupart des cas, cette implémentation suffit à gérer les tâches asynchrones de votre application pendant les tests.
UriIdlingResource
Semblable à CountingIdlingResource, mais le compteur doit être égal à zéro pour une période spécifique avant que la ressource ne soit considérée comme inactive. Ce délai d'attente supplémentaire prend en compte les requêtes réseau consécutives, où une application de votre thread peut effectuer une nouvelle requête immédiatement après avoir reçu une réponse à une requête précédente.
IdlingThreadPoolExecutor
Implémentation personnalisée de ThreadPoolExecutor qui suit le nombre total de tâches en cours d'exécution dans les pools de threads créés. Cette classe utilise un objet CountingIdlingResource pour gérer le compteur des tâches actives.
IdlingScheduledThreadPoolExecutor
Implémentation personnalisée de ScheduledThreadPoolExecutor. Elle offre les mêmes fonctionnalités que la classe IdlingThreadPoolExecutor, mais elle peut également assurer le suivi des tâches planifiées ou planifiées pour une exécution périodique.

Créer votre propre ressource idling

Lorsque vous utilisez des ressources inactives dans les tests de votre application, vous devrez peut-être fournir une gestion ou une journalisation personnalisées des ressources. Dans ce cas, les implémentations listées dans la section précédente peuvent ne pas suffire. Dans ce cas, vous pouvez étendre l'une de ces implémentations de ressources d'inactivité ou créer la vôtre.

Si vous implémentez votre propre fonctionnalité de ressource d'inactivité, gardez à l'esprit les bonnes pratiques suivantes, en particulier la première:

Appeler les transitions vers l'état inactif en dehors des vérifications d'inactivité.
Une fois que votre application est inactive, appelez onTransitionToIdle() en dehors de toute implémentation de isIdleNow(). Ainsi, Espresso n'effectue pas de deuxième vérification inutile pour déterminer si une ressource inactive donnée est inactive.

L'extrait de code suivant illustre cette recommandation:

Kotlin

fun isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

fun backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}

Java

public void isIdle() {
    // DON'T call callback.onTransitionToIdle() here!
}

public void backgroundWorkDone() {
    // Background work finished.
    callback.onTransitionToIdle() // Good. Tells Espresso that the app is idle.

    // Don't do any post-processing work beyond this point. Espresso now
    // considers your app to be idle and moves on to the next test action.
}
Enregistrez les ressources inactives avant d'en avoir besoin.

Les avantages de synchronisation associés aux ressources inactives ne prennent effet qu'après le premier appel d'Espresso de la méthode isIdleNow() de ces ressources.

La liste suivante présente plusieurs exemples de cette propriété:

  • Si vous enregistrez une ressource d'inactivité dans une méthode annotée avec @Before, celle-ci prend effet à la première ligne de chaque test.
  • Si vous enregistrez une ressource d'inactivité dans un test, elle prend effet lors de la prochaine action basée sur Espresso. Ce comportement se produit même si l'action suivante se trouve dans le même test que l'instruction qui enregistre la ressource d'inactivité.
Annulez l'enregistrement des ressources inactives une fois que vous avez fini de les utiliser.

Pour conserver les ressources système, vous devez annuler l'enregistrement des ressources inactives dès que vous n'en avez plus besoin. Par exemple, si vous enregistrez une ressource inactive dans une méthode annotée avec @Before, il est préférable d'annuler l'enregistrement de cette ressource dans une méthode correspondante annotée avec @After.

Utilisez un registre d'inactivité pour enregistrer et annuler l'enregistrement des ressources inactives.

En utilisant ce conteneur pour les ressources d'inactivité de votre application, vous pouvez enregistrer et annuler l'enregistrement de ces ressources à plusieurs reprises si nécessaire, tout en observant un comportement cohérent.

Ne conservez qu'un état d'application simple dans les ressources d'inactivité.

Par exemple, les ressources d'inactivité que vous implémentez et enregistrez ne doivent pas contenir de références à des objets View.

Enregistrer les ressources inactives

Espresso fournit une classe de conteneur dans laquelle vous pouvez placer les ressources inactives de votre application. Cette classe, appelée IdlingRegistry, est un artefact autonome qui introduit un coût minimal pour votre application. Elle vous permet également d'effectuer les étapes suivantes pour améliorer la gestion de votre application:

  • Créez une référence à IdlingRegistry, au lieu des ressources inactives qu'il contient, dans les tests de votre application.
  • Conservez les différences au niveau de la collection de ressources inactives que vous utilisez pour chaque variante de compilation.
  • Définissez des ressources inactives dans les services de votre application, plutôt que dans les composants d'interface utilisateur qui font référence à ces services.

Intégrer des ressources inactives dans votre application

Bien que vous puissiez ajouter des ressources d'inactivité à une application de plusieurs manières, une approche en particulier gère l'encapsulation de votre application tout en vous permettant de spécifier une opération particulière représentée par une ressource d'inactivité donnée.

Lorsque vous ajoutez des ressources d'inactivité à votre application, nous vous recommandons vivement de placer la logique de ces ressources dans l'application elle-même et de n'effectuer que les opérations d'inscription et de désinscription dans vos tests.

Bien que vous créiez une situation inhabituelle d'utilisation d'une interface de test uniquement dans le code de production en suivant cette approche, vous pouvez encapsuler les ressources inactives autour du code que vous avez déjà, tout en conservant la taille de l'APK et le nombre de méthodes de votre application.

Autres approches

Si vous préférez ne pas avoir de logique de ressources inactives dans le code de production de votre application, il existe plusieurs autres stratégies d'intégration viables:

  • Créez des variantes de compilation, telles que les types de produit Gradle, et n'utilisez les ressources d'inactivité que dans la version de débogage de votre application.
  • Utilisez un framework d'injection de dépendances tel que Dagger pour injecter dans vos tests le graphique des dépendances des ressources inactives de votre application. Si vous utilisez Dagger 2, l'injection elle-même doit provenir d'un sous-composant.
  • Implémentez une ressource d'inactivité dans les tests de votre application et exposez la partie de l'implémentation de votre application qui doit être synchronisée dans ces tests.

    Attention : Bien que cette décision de conception semble créer une référence autonome aux ressources inactives, elle rompt également l'encapsulation dans toutes les applications, sauf les plus simples.

Ressources supplémentaires

Pour en savoir plus sur l'utilisation d'Espresso dans les tests Android, consultez les ressources suivantes.

Exemples