Adapter vos tests grâce aux appareils gérés par Gradle

En utilisant des appareils gérés par Gradle, vous améliorez la cohérence, les performances et la fiabilité de vos tests d'instrumentation automatisés. Cette fonctionnalité, disponible à partir du niveau d'API 27, vous permet de configurer des appareils de test physiques virtuels ou distants dans les fichiers Gradle de votre projet. Le système de compilation utilise les configurations pour gérer entièrement ces appareils lors de l'exécution des tests automatisés, c'est-à-dire pour les créer, les déployer et les supprimer.

Grâce à cette fonctionnalité, Gradle a accès aux tests que vous exécutez, mais aussi au cycle de vie des appareils, ce qui améliore la qualité de votre expérience de test, à plusieurs niveaux :

  • Gradle gère les problèmes liés aux appareils pour assurer l'exécution de vos tests.
  • Pour les appareils virtuels, utilise les instantanés de l'émulateur pour améliorer le temps de démarrage ainsi que l'utilisation de la mémoire des appareils et pour restaurer l'état des appareils entre les tests.
  • Gradle met en cache les résultats des tests et ne réexécute que les tests susceptibles de donner des résultats différents.
  • Gradle offre un environnement cohérent pour l'exécution de vos tests, qu'il s'agisse d'exécutions locales ou d'exécutions distantes.

Créer un appareil virtuel géré par Gradle

Vous pouvez spécifier un appareil virtuel que Gradle devra utiliser pour tester votre application dans votre fichier de compilation au niveau du module. L'exemple de code suivant crée un Pixel 2 exécutant le niveau 30 de l'API sous forme d'appareil géré par Gradle.

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // Use only API levels 27 and higher.
          apiLevel = 30
          // To include Google services, use "google".
          systemImageSource = "aosp"
        }
      }
    }
  }
}

Définir des groupes d'appareils

Pour vous aider à adapter vos tests à plusieurs configurations d'appareils, couvrant par exemple différents niveaux d'API et facteurs de forme, vous pouvez définir plusieurs appareils gérés par Gradle et les ajouter à un groupe nommé. Gradle peut ensuite exécuter vos tests sur tous les appareils du groupe en parallèle.

L'exemple ci-dessous montre deux appareils ajoutés à un groupe d'appareils appelé phoneAndTablet.

Kotlin

testOptions {
  managedDevices {
    localDevices {
      create("pixel2api29") { ... }
      create("nexus9api30") { ... }
    }
    groups {
      create("phoneAndTablet") {
        targetDevices.add(devices["pixel2api29"])
        targetDevices.add(devices["nexus9api30"])
      }
    }
  }
}

Groovy

testOptions {
  managedDevices {
    localDevices {
      pixel2api29 { ... }
      nexus9api30 { ... }
    }
    groups {
      phoneAndTablet {
        targetDevices.add(devices.pixel2api29)
        targetDevices.add(devices.nexus9api30)
      }
    }
  }
}

Exécuter vos tests

Pour exécuter vos tests à l'aide des appareils gérés par Gradle que vous avez configurés, utilisez la commande suivante. device-name est le nom de l'appareil que vous avez configuré dans votre script de compilation Gradle (pixel2api30, par exemple) et BuildVariant est la variante de compilation de l'application à tester.

Sous Windows :

gradlew device-nameBuildVariantAndroidTest

Sous Linux ou macOS :

./gradlew device-nameBuildVariantAndroidTest

Pour exécuter vos tests sur un groupe d'appareils gérés par Gradle, utilisez les commandes suivantes.

Sous Windows :

gradlew group-nameGroupBuildVariantAndroidTest

Sous Linux ou macOS :

./gradlew group-nameGroupBuildVariantAndroidTest

Le résultat du test inclut un chemin d'accès à un fichier HTML contenant le rapport de test. Vous pouvez également importer les résultats des tests dans Android Studio pour une analyse plus approfondie en cliquant sur Run > Test History (Exécuter > Historique des tests) dans l'IDE.

Activer la segmentation des tests

Les appareils gérés par Gradle gèrent la segmentation des tests, ce qui vous permet de scinder votre suite de tests sur plusieurs instances d'appareils virtuels identiques appelées segments, qui s'exécutent en parallèle. La segmentation des tests peut vous aider à réduire la durée d'exécution totale des tests, mais nécessite des ressources de calcul supplémentaires.

Pour définir le nombre de segments à utiliser dans une exécution de test, définissez les éléments suivants dans votre fichier gradle.properties :

android.experimental.androidTest.numManagedDeviceShards=<number_of_shards>

Lorsque vous exécutez vos tests avec cette option, les appareils gérés par Gradle provisionnent le nombre de segments que vous spécifiez pour chaque profil d'appareil dans l'exécution du test. Par exemple, si vous avez déployé vos tests sur un groupe de trois appareils et que vous avez attribué la valeur 2 à numManagedDeviceShards, les appareils gérés par Gradle provisionneront au total six appareils virtuels pour l'exécution de votre test.

Une fois les tests terminés, Gradle écrit les résultats des tests dans un fichier .proto pour chaque segment utilisé dans l'exécution du test.

Utiliser des appareils de test automatisés

Les appareils gérés par Gradle prennent en charge un type d'appareil émulateur appelé ATD (Automated Test Device). Celui-ci est optimisé pour réduire la consommation de ressources processeur et de mémoire lors de l'exécution de vos tests d'instrumentation. Les ATD améliorent les performances d'exécution de plusieurs manières :

  • Ils suppriment les applications préinstallées qui ne sont généralement pas utiles pour tester votre application.
  • Ils désactivent certains services d'arrière-plan qui ne sont généralement pas utiles pour tester votre application.
  • Ils désactivent le rendu matériel.

Avant de commencer, pensez à mettre à jour Android Emulator pour disposer de la dernière version disponible. Spécifiez ensuite une image "-atd" lorsque vous définissez un appareil géré par Gradle dans votre fichier de compilation au niveau du module, comme indiqué ci-dessous :

Kotlin

android {
  testOptions {
    managedDevices {
      localDevices {
        create("pixel2api30") {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

Groovy

android {
  testOptions {
    managedDevices {
      localDevices {
        pixel2api30 {
          // Use device profiles you typically see in Android Studio.
          device = "Pixel 2"
          // ATDs currently support only API level 30.
          apiLevel = 30
          // You can also specify "google-atd" if you require Google Play Services.
          systemImageSource = "aosp-atd"
        }
      }
    }
  }
}

Vous pouvez également créer des groupes d'appareils, comme vous le feriez avec d'autres appareils gérés par Gradle. Pour profiter davantage des améliorations liées aux performances, vous pouvez également utiliser des ATD avec la fonctionnalité de segmentation des tests pour réduire la durée d'exécution totale de votre suite de tests.

Quels éléments sont supprimés dans les images ATD ?

En plus de fonctionner en mode headless, les ATD optimisent également les performances en supprimant ou en désactivant les applications et services qui ne sont généralement pas nécessaires pour tester le code de votre application. Le tableau ci-dessous présente les composants que nous avons supprimés ou désactivés dans les images ATD, ainsi qu'une description expliquant pourquoi ils ne sont pas nécessairement utiles.

Éléments supprimés dans les images ATD Raison pour laquelle ils ne sont pas indispensables dans le cadre des tests automatisés
Applications Google :
  • Messagerie
  • Maps
  • Chrome
  • Messages
  • Play Store et autres
Vos tests automatisés doivent se concentrer sur la logique de votre application, en supposant que les autres applications ou la plate-forme fonctionnent correctement.

Espresso-Intents vous permet d'associer et de valider vos intents sortants, et même de fournir des bouchons de réponse à la place des réponses d'intent réelles.

Paramètres, applications et services :
  • CarrierConfig
  • EmergencyInfo
  • OneTimeInitializer
  • PhotoTable (économiseurs d'écran)
  • Provisionnement
  • Application Paramètres
  • StorageManager
  • Configuration de l'APN de téléphonie
  • WallpaperCropper
  • WallpaperPicker
Ces applications présentent aux utilisateurs finaux une IUG permettant de modifier les paramètres de la plate-forme, de configurer leur appareil ou d'en gérer le stockage. Ces paramètres n'entrent généralement pas dans le cadre des tests automatisés au niveau de l'application.


Remarque : Le fournisseur de paramètres est toujours disponible dans l'image ATD.

SystemUI Vos tests automatisés doivent se concentrer sur la logique de votre application, en supposant que les autres applications ou la plate-forme fonctionnent correctement.
Applications et services AOSP :
  • Browser2
  • Agenda
  • Camera2
  • Contacts
  • Téléphone
  • DeskClock
  • Gallery2
  • LatinIME
  • Launcher3QuickStep
  • Musique
  • QuickSearchBox
  • SettingsIntelligence
Ces applications et services n'entrent généralement pas dans le cadre des tests automatisés du code de votre application.

Utiliser des appareils Firebase Test Lab

Vous pouvez exécuter vos tests d'instrumentation automatisés à grande échelle sur des appareils Firebase Test Lab lorsque vous utilisez des appareils gérés par Gradle. Test Lab vous permet d'exécuter vos tests simultanément sur une large gamme d'appareils Android, à la fois physiques et virtuels. Ces tests sont exécutés dans des centres de données Google distants. Grâce à la prise en charge des appareils gérés par Gradle, le système de compilation peut gérer entièrement l'exécution des tests sur ces appareils Test Lab, en fonction de vos configurations.

Premiers pas

Les étapes suivantes décrivent comment commencer à utiliser des appareils Firebase Test Lab avec des appareils gérés par Gradle. Notez que ces étapes utilisent la gcloud CLI pour fournir des identifiants utilisateur, ce qui peut ne pas s'appliquer à tous les environnements de développement. Pour en savoir plus sur le processus d'authentification à utiliser pour vos besoins, consultez la section Fonctionnement des identifiants par défaut de l'application.

  1. Pour créer un projet Firebase, accédez à la console Firebase. Cliquez sur Add project (Ajouter un projet) et suivez les instructions à l'écran pour créer un projet. Mémorisez l'ID de votre projet.

  2. Pour installer la Google Cloud CLI, suivez la procédure décrite dans la section Installer la gcloud CLI.

  3. Configurez votre environnement local.

    1. Associez votre projet Firebase dans gcloud :

      gcloud config set project FIREBASE_PROJECT_ID
      
    2. Autorisez l'utilisation de vos identifiants utilisateur pour accéder à l'API. Nous vous recommandons de procéder à l'autorisation en transmettant un fichier JSON de compte de service à Gradle à l'aide du DSL dans le script de compilation au niveau du module :

      Kotlin

      firebaseTestLab {
        ...
        serviceAccountCredentials.set(file(SERVICE_ACCOUNT_JSON_FILE))
      }
      

      Groovy

      firebaseTestLab {
        ...
        serviceAccountCredentials = file(SERVICE_ACCOUNT_JSON_FILE)
      }
      

      Vous pouvez également autoriser manuellement l'accès à l'aide de la commande de terminal suivante :

      gcloud auth application-default login
      
    3. (Facultatif) Ajoutez votre projet Firebase en tant que projet de quota. Cette étape n'est nécessaire que si vous dépassez le quota sans frais pour Test Lab.

      gcloud auth application-default set-quota-project FIREBASE_PROJECT_ID
      
  4. Activez les API requises.

    Sur la page de la bibliothèque d'API de la console pour les développeurs Google, activez l'API Cloud Testing et l'API Cloud Tool Results en saisissant ces noms d'API dans le champ de recherche situé en haut de la console, puis en cliquant sur Enable API (Activer l'API) dans la vue d'ensemble pour chaque API.

  5. Configurez votre projet Android.

    1. Ajoutez le plug-in Firebase Test Lab au script de compilation de premier niveau :

      Kotlin

      plugins {
        ...
        id("com.google.firebase.testlab") version "0.0.1-alpha05" apply false
      }
      

      Groovy

      plugins {
        ...
        id 'com.google.firebase.testlab' version '0.0.1-alpha05' apply false
      }
      
    2. Activez les types d'appareils personnalisés dans le fichier gradle.properties :

      android.experimental.testOptions.managedDevices.customDevice=true
      
    3. Ajoutez le plug-in Firebase Test Lab dans le script de compilation au niveau du module :

      Kotlin

      plugins {
       ...
       id "com.google.firebase.testlab"
      }
      

      Groovy

      plugins {
       ...
       id 'com.google.firebase.testlab'
      }
      

Spécifier un appareil Test Lab

Vous pouvez spécifier un appareil Firebase Test Lab que Gradle utilisera pour tester votre application dans le script de compilation au niveau du module. L'exemple de code suivant crée un Pixel 3 exécutant le niveau d'API 30 en tant qu'appareil Test Lab géré par Gradle et appelé ftlDevice. Le bloc firebaseTestLab {} est disponible lorsque vous appliquez le plug-in com.google.firebase.testlab à votre module.

Kotlin

firebaseTestLab {
  managedDevices {
    create("ftlDevice") {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

Groovy

firebaseTestLab {
  managedDevices {
    ftlDevice {
      device = "Pixel3"
      apiLevel = 30
    }
  }
  ...
}

Pour définir un groupe d'appareils gérés par Gradle, y compris des appareils Firebase Test Lab, consultez Définir des groupes d'appareils.

Pour exécuter vos tests, utilisez les mêmes commandes que pour d'autres appareils gérés par Gradle. Notez que Gradle n'exécute pas de tests en parallèle ou n'est pas compatible avec d'autres configurations Google Cloud CLI pour les appareils Test Lab.

Optimiser les exécutions de test avec la segmentation intelligente

Les tests sur des appareils Test Lab gérés par Gradle sont compatibles avec la segmentation intelligente. La segmentation intelligente répartit automatiquement vos tests sur plusieurs segments de sorte que chaque segment s'exécute à peu près en même temps, ce qui réduit les efforts d'allocation manuelle et la durée globale d'exécution des tests. La segmentation intelligente utilise l'historique de vos tests ou des informations sur leur durée d'exécution précédente pour les répartir de manière optimale. Notez que vous devez disposer de la version 0.0.1-alpha05 du plug-in Gradle pour Firebase Test Lab afin d'utiliser la segmentation intelligente.

Pour activer la segmentation intelligente, spécifiez la durée des tests au sein de chaque segment. Vous devez définir la durée cible des segments sur une durée inférieure à timeoutMinutes d'au moins cinq minutes pour éviter que les segments ne soient annulés avant la fin des tests.

firebaseTestLab {
  ...
  testOptions {
    targetedShardDurationMinutes = 2
  }
}

Pour en savoir plus, consultez les options DSL des appareils Firebase Test Lab.

DSL mis à jour pour les appareils Test Lab

Vous pouvez configurer d'autres options DSL pour personnaliser vos exécutions de test ou migrer à partir d'autres solutions que vous utilisez peut-être déjà. Consultez certaines de ces options, comme décrit dans l'extrait de code suivant.

firebaseTestLab {
  ...

  /**
   * A path to a JSON file that contains service account credentials to access to
   * a Firebase Test Lab project.
   */
  serviceAccountCredentials.set(file("your_service_account_credentials.json"))


  testOptions {
    fixture {
      /**
       * Whether to grant permissions on the device before tests begin.
       * Available options are "all" or "none".
       *
       * Default value is "all".
       */
      grantedPermissions = "all"

      /**
       * Map of files to push to the device before starting the test.
       *
       * The key is the location on the device.
       * The value is the location of the file, either local or in Google Cloud.
       */
      extraDeviceFiles["/sdcard/dir1/file1.txt"] = "local/file.txt"
      extraDeviceFiles["/sdcard/dir2/file2.txt"] = "gs://bucket/file.jpg"

      /**
       * The name of the network traffic profile.
       *
       * Specifies network conditions to emulate when running tests.
       *
       * Default value is empty.
       */
      networkProfile = "LTE"
    }

    execution {
      /**
       * The maximum time to run the test execution before cancellation,
       * measured in minutes. Does not include the setup or teardown of device,
       * and is handled server-side.
       *
       * The maximum possible testing time is 45 minutes on physical devices
       * and 60 minutes on virtual devices.
       *
       * Defaults to 15 minutes.
       */
       timeoutMinutes = 30

      /**
       * Number of times the test should be rerun if tests fail.
       * The number of times a test execution should be retried if one
       * or more of its test cases fail.
       *
       * The max number of times is 10.
       *
       * The default number of times is 0.
       */
      maxTestReruns = 2

      /**
       * Ensures only a single attempt is made for each execution if
       * an infrastructure issue occurs. This doesn't affect `maxTestReruns`.
       * Normally, two or more attempts are made by Firebase Test Lab if a
       * potential infrastructure issue is detected. This is best enabled for
       * latency sensitive workloads. The number of execution failures might be
       * significantly greater with `failFast` enabled.
       *
       * Defaults to false.
       */
      failFast = false

      /**
       * The number of shards to split the tests across.
       *
       * Default to 0 for no sharding.
       */
      numUniformShards = 20
    }

    /**
     * For smart sharding, the target length of time each shard should takes in
     * minutes. Maxes out at 50 shards for physical devices and 100 shards for
     * virtual devices.
     *
     * Only one of numUniformShards or targetedShardDurationMinutes can be set.
     *
     * Defaults to 0 for no smart sharding.
     */
     targetedShardDurationMinutes = 15
    }

    results {
      /**
       * The name of the Google storage bucket to store the test results in.
       *
       * If left unspecified, the default bucket is used.
       *
       * Please refer to Firebase Test Lab permissions for required permissions
       * for using the bucket.
       */
      cloudStorageBucket = "bucketLocationName"

      /**
       * Name of test results for the Firebase console history list.
       * All tests results with the same history name are grouped
       * together in the Firebase console in a time-ordered test history list.
       *
       * Defaults to the application label in the APK manifest in Flank/Fladle.
       */
      resultsHistoryName = "application-history"

      /**
       * List of paths to copy from the test device's storage to the test
       * results folder. These must be absolute paths under /sdcard or
       * /data/local/tmp.
       */
      directoriesToPull.addAll(
        "/sdcard/path/to/something"
      )

      /**
       * Whether to enable video recording during the test.
       *
       * Disabled by default.
       */
      recordVideo = false

      /**
       * Whether to enable performance metrics. If enabled, monitors and records
       * performance metrics such as CPU, memory, and network usage.
       *
       * Defaults to false.
       */
      performanceMetrics = true
  }
}