Cette catégorie de test d'instrumentation n'est pas très différente de celles ciblant les applications Android standards. Il est important de noter que l'application de test qui inclut l'instrumentation doit être signée avec le même certificat que l'application qu'elle cible.
Notez que ce guide suppose que vous avez déjà des connaissances sur le workflow de l'arborescence source de la plate-forme. Si ce n'est pas le cas, veuillez consulter la section Exigences. L'exemple présenté ici consiste à écrire un nouveau test d'instrumentation avec le package cible défini sur son propre package d'application de test. Si vous ne connaissez pas ce concept, veuillez lire l'introduction aux tests de la plate-forme.
Ce guide utilise le test suivant comme exemple :
- frameworks/base/packages/Shell/tests
Nous vous recommandons de parcourir le code pour vous faire une idée avant de continuer.
Choisir un emplacement source
Étant donné que le test d'instrumentation ciblera une application, la convention consiste à placer le code source du test dans un répertoire tests à la racine du répertoire source de votre composant dans l'arborescence source de la plate-forme.
Fichier manifeste
Comme une application standard, chaque module de test d'instrumentation a besoin d'un fichier manifeste. Si vous nommez le fichier AndroidManifest.xml et le fournissez à côté de Android.mk pour votre module de test, il sera inclus automatiquement par le makefile principal BUILD_PACKAGE.
Avant de continuer, nous vous recommandons vivement de consulter la présentation du fichier manifeste de l'application.
Vous y trouverez une présentation des composants de base d'un fichier manifeste et de leurs fonctionnalités.
La dernière version du fichier manifeste pour l'exemple de modification Gerrit est disponible à l'adresse suivante : https://android.googlesource.com/platform/frameworks/base/+/android17-release/packages/Shell/tests/AndroidManifest.xml
Voici un instantané pour plus de commodité :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell.tests">
<application>
<uses-library android:name="android.test.runner" />
<activity
android:name="com.android.shell.ActionSendMultipleConsumerActivity"
android:label="ActionSendMultipleConsumer"
android:theme="@android:style/Theme.NoDisplay"
android:noHistory="true"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.shell"
android:label="Tests for Shell" />
</manifest>
Voici quelques remarques sur le fichier manifeste :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell.tests">
L'attribut package est le nom du package d'application. Il s'agit de l'identifiant unique que le framework d'application Android utilise pour identifier une application (ou, dans ce contexte, votre application de test). Chaque utilisateur du système ne peut installer qu'une seule application portant ce nom de package.
Comme il s'agit d'un package d'application de test, indépendant du package d'application testé, un nom de package différent doit être utilisé. Une convention courante consiste à ajouter un suffixe .test.
De plus, cet attribut package est identique à ce que
ComponentName#getPackageName()
renvoie, ainsi qu'à celui que vous utiliseriez pour interagir avec différentes sous
commandes pm via adb shell.
Veuillez également noter que, bien que le nom du package soit généralement du même style qu'un nom de package Java, il n'a en fait que très peu de choses à voir avec lui. En d'autres termes, votre package d'application (ou de test) peut contenir des classes avec n'importe quel nom de package. Toutefois, vous pouvez opter pour la simplicité et avoir le nom de package Java de premier niveau dans votre application ou votre test identique au nom du package d'application.
<uses-library android:name="android.test.runner" />
Cela est nécessaire pour tous les tests d'instrumentation, car les classes associées sont empaquetées dans un fichier de bibliothèque JAR de framework distinct. Par conséquent, des entrées de chemin de classe supplémentaires sont requises lorsque le package de test est appelé par le framework d'application.
android:targetPackage="com.android.shell"
Cela définit le package cible de l'instrumentation sur com.android.shell.
Lorsque l'instrumentation est appelée via la commande am instrument, le framework redémarre le processus com.android.shell et injecte le code d'instrumentation dans le processus pour l'exécution du test. Cela signifie également que le code de test aura accès à toutes les instances de classe exécutées dans l'application testée et pourra manipuler l'état en fonction des hooks de test exposés.
Fichier de configuration simple
Chaque nouveau module de test doit disposer d'un fichier de configuration pour diriger le système de compilation avec les métadonnées du module, les dépendances au moment de la compilation et les instructions d'empaquetage. Dans la plupart des cas, l'option de fichier Blueprint basée sur Soong est suffisante. Pour en savoir plus, consultez la section Configuration simple des tests.
Fichier de configuration complexe
Pour les tests plus complexes, vous devez également écrire un fichier de configuration de test pour l'outil de test d'Android, Trade Federation.
La configuration de test peut spécifier des options de configuration spéciales pour l'appareil et des arguments par défaut à fournir à la classe de test.
La dernière version du fichier de configuration pour l'exemple de modification Gerrit est disponible à l'adresse suivante : frameworks/base/packages/Shell/tests/AndroidTest.xml
Voici un instantané pour plus de commodité :
<configuration description="Runs Tests for Shell.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ShellTests.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<option name="test-tag" value="ShellTests" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.shell.tests" />
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
Voici quelques remarques sur le fichier de configuration de test :
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ShellTests.apk"/>
</target_preparer>
Cela indique à Trade Federation d'installer ShellTests.apk sur l'appareil cible à l'aide d'un target_preparer spécifié. De nombreux préparateurs cibles sont disponibles pour les développeurs dans Trade Federation. Ils peuvent être utilisés pour s'assurer que l'appareil est correctement configuré avant l'exécution du test.
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.shell.tests"/>
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>
Cela spécifie la classe de test Trade Federation à utiliser pour exécuter le test et transmet le package sur l'appareil à exécuter et le framework de l'exécuteur de test, qui est JUnit dans ce cas.
Pour en savoir plus sur les configurations des modules de test, cliquez ici.
Fonctionnalités JUnit4
L'utilisation de la bibliothèque android-support-test comme exécuteur de test permet d'adopter de nouvelles classes de test de style JUnit4. L'exemple de modification Gerrit contient une utilisation très basique de ses fonctionnalités.
La dernière version du code source pour l'exemple de modification Gerrit est disponible à l'adresse suivante : frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
Bien que les modèles de test soient généralement spécifiques aux équipes de composants, il existe des modèles d'utilisation généralement utiles.
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {
Une différence significative dans JUnit4 est que les tests ne sont plus obligés d'hériter d'une classe de test de base commune. Au lieu de cela, vous écrivez des tests dans des classes Java simples et utilisez une annotation pour indiquer certaines configurations et contraintes de test. Dans cet exemple, nous indiquons que cette classe doit être exécutée en tant que test Android JUnit4.
L'annotation @SmallTest a spécifié une taille de test pour l'ensemble de la classe de test : toutes les méthodes de test ajoutées à cette classe de test héritent de cette annotation de taille de test. configuration de la classe de pré-test, suppression après le test et suppression après la classe de test : semblable aux méthodes setUp et tearDown dans JUnit4.
L'annotation Test est utilisée pour annoter le test réel.
@Before
public void setup() {
...
@Test
public void testGetProvider_shouldCacheProvider() {
...
L'annotation @Before est utilisée sur les méthodes par JUnit4 pour effectuer la configuration avant le test.
Bien qu'elle ne soit pas utilisée dans cet exemple, il existe également @After pour la suppression après le test.
De même, les annotations @BeforeClass et @AfterClass peuvent être utilisées sur les méthodes par JUnit4 pour effectuer la configuration avant d'exécuter tous les tests d'une classe de test, puis la suppression. Notez que les méthodes de configuration et de suppression au niveau de la classe doivent être statiques.
Quant aux méthodes de test, contrairement aux versions antérieures de JUnit, elles n'ont plus besoin de commencer le nom de la méthode par test. Au lieu de cela, chacune d'elles doit être annotée avec @Test. Comme d'habitude, les méthodes de test doivent être publiques, ne pas déclarer de valeur renvoyée, ne pas accepter de paramètres et peuvent générer des exceptions.
Context context = InstrumentationRegistry.getTargetContext();
Étant donné que les tests JUnit4 ne nécessitent plus de classe de base commune, il n'est plus
nécessaire d'obtenir Context instances via getContext() ou
getTargetContext() via des méthodes de classe de base. Au lieu de cela, le nouvel exécuteur de test
les gère via InstrumentationRegistry
où la configuration contextuelle et environnementale créée par le framework d'instrumentation est
stockée. Grâce à cette classe, vous pouvez également appeler :
getInstrumentation(): l'instance de la classeInstrumentationgetArguments(): les arguments de ligne de commande transmis àam instrumentvia-e <key> <value>
Compiler et tester en local
Pour les cas d'utilisation les plus courants, utilisez Atest.
Pour les cas plus complexes nécessitant une personnalisation plus poussée, suivez les instructions d'instrumentation.