Cartographie des tests

Il s'agit d'une brève introduction au mappage de tests et d'une explication sur la façon de commencer à configurer facilement des tests dans le projet Android Open Source (AOSP).

À propos du mappage de tests

Le mappage de tests est une approche basée sur Gerrit qui permet aux développeurs de créer des règles de test avant et après soumission directement dans l'arborescence source Android et de laisser les décisions des branches et des appareils à tester à l'infrastructure de test elle-même. Les définitions de mappage de test sont des fichiers JSON nommés TEST_MAPPING qui peuvent être placés dans n'importe quel répertoire source.

Atest peut utiliser les fichiers TEST_MAPPING pour exécuter des tests de pré-soumission dans les répertoires associés. Avec le mappage de tests, vous pouvez ajouter le même ensemble de tests pour pré-soumettre des contrôles avec une simple modification dans l'arborescence des sources Android.

Voir ces exemples :

Ajouter des tests de pré-soumission à TEST_MAPPING pour services.core

Ajouter des tests de pré-soumission à TEST_MAPPING pour Tools/Dexter à l'aide d'importations

La cartographie des tests s'appuie sur le faisceau de tests de la Trade Federation (TF) pour l'exécution des tests et le reporting des résultats.

Définir des groupes de tests

Le mappage de tests regroupe les tests via un groupe de tests . Le nom d'un groupe de test peut être n'importe quelle chaîne. Par exemple, la présoumission peut concerner un groupe de tests à exécuter lors de la validation des modifications. Et les tests post-soumission peuvent être utilisés pour valider les builds après la fusion des modifications.

Règles de script de génération de package

Pour que Trade Federation Test Harness puisse exécuter les modules de test de mappage de tests pour une version donnée, ces modules doivent avoir test_suite défini pour Soong ou LOCAL_COMPATIBILITY_SUITE défini pour Make sur l'une de ces deux suites :

  • tests généraux : tests qui ne dépendent pas de fonctionnalités spécifiques à l'appareil (comme le matériel spécifique au fournisseur que la plupart des appareils n'ont pas). La plupart des tests doivent figurer dans la suite de tests généraux, même s'ils sont spécifiques à un ABI, à un nombre de bits ou à des fonctionnalités matérielles telles que HWASan (il existe une cible test_suites distincte pour chaque ABI), et même s'ils doivent s'exécuter sur un appareil.
  • tests de périphérique - tests qui dépendent des fonctionnalités spécifiques au périphérique. Généralement, ces tests se trouvent sous vendor/ . Étant donné que « spécifique à l'appareil » ne fait pas référence aux fonctionnalités ABI ou SoC que d'autres appareils pourraient ou non avoir, mais uniquement aux fonctionnalités uniques à un appareil, cela s'applique autant aux tests JUnit qu'aux tests natifs GTest (qui devraient généralement être general-tests même s'ils sont spécifiques à l'ABI).

Exemples:

Android.bp: test_suites: ["general-tests"],
Android.mk: LOCAL_COMPATIBILITY_SUITE := general-tests

Configurer les tests à exécuter dans une suite de tests

Pour qu'un test s'exécute dans une suite de tests, le test :

  • ne doit avoir aucun fournisseur de build.
  • doit nettoyer une fois terminé, par exemple en supprimant tous les fichiers temporaires générés pendant le test.
  • modifier les paramètres du système à la valeur par défaut ou à la valeur d'origine.
  • ne doit pas supposer qu'un périphérique est dans un certain état, par exemple prêt pour le root. La plupart des tests ne nécessitent pas les privilèges root pour s'exécuter. Si un test doit nécessiter root, il doit le spécifier avec un RootTargetPreparer dans son AndroidTest.xml , comme dans l'exemple suivant :
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>

Créer des fichiers de mappage de test

Pour le répertoire nécessitant une couverture de test, ajoutez simplement un fichier JSON TEST_MAPPING ressemblant à l'exemple ci-dessous. Ces règles garantiront que les tests s'exécutent lors des vérifications préalables à la soumission lorsque des fichiers sont touchés dans ce répertoire ou l'un de ses sous-répertoires.

Suivez un exemple

Voici un exemple de fichier TEST_MAPPING (au format JSON mais avec commentaires pris en charge) :

{
  "presubmit": [
    // JUnit test with options and file patterns.
    {
      "name": "CtsWindowManagerDeviceTestCases",
      "options": [
        {
          "include-annotation": "android.platform.test.annotations.RequiresDevice"
        }
      ],
      "file_patterns": ["(/|^)Window[^/]*\\.java", "(/|^)Activity[^/]*\\.java"]
    },
    // Device-side GTest with options.
    {
      "name" : "hello_world_test",
      "options": [
        {
          "native-test-flag": "\"servicename1 servicename2\""
        },
        {
          "native-test-timeout": "6000"
        }
      ]
    }
    // Host-side GTest.
    {
      "name" : "net_test_avrcp",
      "host" : true
    }
  ],
  "postsubmit": [
    {
      "name": "CtsWindowManagerDeviceTestCases"
    }
  ],
  "imports": [
    {
      "path": "frameworks/base/services/core/java/com/android/server/am"
    }
  ]
}

Définir les attributs

Dans l'exemple ci-dessus, presubmit et postsubmit sont les noms de chaque groupe de test . Voir Définition de groupes de tests pour plus d'informations sur les groupes de tests.

Le nom du module de test ou le nom du test d'intégration de la Trade Federation (chemin de la ressource vers le fichier XML de test, par exemple uiautomator/uiautomator-demo ) peut être défini dans la valeur de l'attribut name . Notez que le champ de nom ne peut pas utiliser name de classe ou name de méthode de test. Pour affiner les tests à exécuter, vous pouvez utiliser des options telles que include-filter ici. Voir ( exemple d'utilisation du filtre include-filter ).

Le paramètre hôte d'un test indique si le test est un test sans périphérique exécuté sur l'hôte ou non. La valeur par défaut est false , ce qui signifie que le test nécessite l'exécution d'un appareil. Les types de tests pris en charge sont HostGTest pour les binaires GTest et HostTest pour les tests JUnit.

L'attribut file_patterns vous permet de définir une liste de chaînes regex pour faire correspondre le chemin relatif de n'importe quel fichier de code source (par rapport au répertoire contenant le fichier TEST_MAPPING). Dans l'exemple ci-dessus, le test CtsWindowManagerDeviceTestCases s'exécutera en pré-soumission uniquement lorsqu'un fichier Java commençant par Window ou Activity, qui existe dans le même répertoire du fichier TEST_MAPPING ou l'un de ses sous-répertoires, est modifié. Les barres obliques inverses \ doivent être échappées telles qu'elles le sont dans un fichier JSON.

L'attribut importations vous permet d'inclure des tests dans d'autres fichiers TEST_MAPPING sans copier le contenu. Notez que les fichiers TEST_MAPPING dans les répertoires parents du chemin importé seront également inclus. Le mappage de test permet des importations imbriquées ; cela signifie que deux fichiers TEST_MAPPING peuvent s'importer mutuellement et que le mappage de tests est capable de fusionner correctement les tests inclus.

L'attribut options contient des options de ligne de commande TradeFed supplémentaires.

Pour obtenir une liste complète des options disponibles pour un test donné, exécutez :

tradefed.sh run commandAndExit [test_module] --help

Reportez-vous à TradeFed Option Handling pour plus de détails sur le fonctionnement des options.

Exécuter des tests avec Atest

Pour exécuter localement les règles de test de pré-soumission :

  1. Accédez au répertoire contenant le fichier TEST_MAPPING.
  2. Exécutez la commande :
atest

Tous les tests de présoumission configurés dans les fichiers TEST_MAPPING du répertoire courant et de ses répertoires parents sont exécutés. Atest localisera et exécutera deux tests de pré-soumission (A et B).

Il s'agit du moyen le plus simple d'exécuter des tests de pré-soumission dans les fichiers TEST_MAPPING du répertoire de travail actuel (CWD) et des répertoires parents. Atest localisera et utilisera le fichier TEST_MAPPING dans CWD et tous ses répertoires parents.

Structurer le code source

L'exemple suivant montre comment les fichiers TEST_MAPPING peuvent être configurés dans l'arborescence source.

src
├── project_1
│   └── TEST_MAPPING
├── project_2
│   └── TEST_MAPPING
└── TEST_MAPPING

Contenu de src/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "A"
    }
  ]
}

Contenu de src/project_1/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "B"
    }
  ],
  "postsubmit": [
    {
      "name": "C"
    }
  ],
  "other_group": [
    {
      "name": "X"
    }
  ]}

Contenu de src/project_2/TEST_MAPPING :

{
  "presubmit": [
    {
      "name": "D"
    }
  ],
  "import": [
    {
      "path": "src/project_1"
    }
  ]}

Spécifier les répertoires cibles

Vous pouvez spécifier un répertoire cible pour exécuter des tests dans les fichiers TEST_MAPPING de ce répertoire. La commande suivante exécutera deux tests (A, B).

atest --test-mapping src/project_1

Exécuter les règles de test après la soumission

Vous pouvez également utiliser cette commande pour exécuter les règles de test post-soumission définies dans TEST_MAPPING dans src_path (par défaut CWD) et ses répertoires parents :

atest [--test-mapping] [src_path]:postsubmit

Exécutez uniquement les tests qui ne nécessitent aucun appareil

Vous pouvez utiliser l'option --host pour Atest pour exécuter uniquement les tests configurés sur l'hôte qui ne nécessitent aucun périphérique. Sans cette option, Atest exécutera les deux tests, ceux nécessitant un périphérique et ceux exécutés sur l'hôte et ne nécessitant aucun périphérique. Les tests seront exécutés dans deux suites distinctes.

atest [--test-mapping] --host

Identifier les groupes de test

Vous pouvez spécifier des groupes de tests dans la commande Atest. La commande suivante exécutera tous les tests post-soumission liés aux fichiers du répertoire src/project_1, qui ne contient qu'un seul test (C).

Ou vous pouvez utiliser :all pour exécuter tous les tests quel que soit le groupe. La commande suivante exécute quatre tests (A, B, C, X) :

atest --test-mapping src/project_1:all

Inclure les sous-répertoires

Par défaut, l'exécution de tests dans TEST_MAPPING avec Atest exécutera uniquement les tests de pré-soumission configurés dans le fichier TEST_MAPPING dans CWD (ou dans un répertoire donné) et ses répertoires parents. Si vous souhaitez exécuter des tests dans tous les fichiers TEST_MAPPING des sous-répertoires, utilisez l'option --include-subdir pour forcer Atest à inclure également ces tests.

atest --include-subdir

Sans l'option --include-subdir , Atest exécutera uniquement le test A. Avec l'option --include-subdir , Atest exécutera deux tests (A, B).

Les commentaires au niveau de la ligne sont pris en charge

Vous pouvez ajouter un commentaire au format // au niveau de la ligne pour étoffer le fichier TEST_MAPPING avec une description du paramètre qui suit. ATest et Trade Federation prétraiteront le TEST_MAPPING dans un format JSON valide sans commentaires. Pour que le fichier JSON reste propre et facile à lire, seul le commentaire au format // au niveau de la ligne est pris en charge.

Exemple:

{
  // For presubmit test group.
  "presubmit": [
    {
      // Run test on module A.
      "name": "A"
    }
  ]
}