Cette catégorie de test d'instrumentation n'est pas si différente de celle qui cible les applications Android standards. Notez 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, consultez 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 la présentation des tests de plate-forme.
Ce guide utilise le test suivant comme exemple:
- frameworks/base/packages/Shell/tests
Nous vous recommandons de parcourir d'abord le code pour avoir une idée générale avant de continuer.
Choisir un emplacement source
Étant donné que le test d'instrumentation ciblera une application, il est recommandé de placer le code source du test dans un répertoire tests
sous la racine de votre répertoire source de composant dans l'arborescence de sources de la plate-forme.
Pour en savoir plus sur l'emplacement de la source, consultez l'exemple de bout en bout pour les tests d'auto-instrumentation.
Fichier manifeste
Tout comme une application standard, chaque module de test d'instrumentation nécessite 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 automatiquement inclus par le fichier de compilation principal BUILD_PACKAGE
.
Avant de continuer, nous vous recommandons vivement de consulter la présentation du fichier manifeste d'application.
Vous trouverez ici une présentation des composants de base d'un fichier manifeste et de leurs fonctionnalités.
Vous pouvez accéder à la dernière version du fichier manifeste pour l'exemple de modification Gerrit à l'adresse : https://android.googlesource.com/platform/frameworks/base/+/main/packages/Shell/tests/AndroidManifest.xml
Pour plus de commodité, un instantané est inclus:
<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>
Quelques remarques concernant 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 de l'application : il s'agit de l'identifiant unique utilisé par le framework d'application Android pour identifier une application (ou, dans ce contexte, votre application de test). Chaque utilisateur du système ne peut installer qu'une seule application avec 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, et également à celui que vous utiliseriez pour interagir avec diverses sous-commandes pm
via adb shell
.
Notez également que, bien que le nom du package soit généralement du même style que celui d'un package Java, il n'a en réalité que très peu à voir avec celui-ci. En d'autres termes, le package de votre application (ou de votre test) peut contenir des classes avec n'importe quel nom de package. Toutefois, vous pouvez opter pour la simplicité et faire en sorte que le nom du package Java de niveau supérieur dans votre application ou votre test soit identique au nom du package de l'application.
<uses-library android:name="android.test.runner" />
Cela est obligatoire 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 du code d'instrumentation dans le processus pour l'exécution des tests. 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 qu'il pourra peut-être 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 de packaging. Dans la plupart des cas, l'option de fichier de plan basée sur Soong est suffisante. Pour en savoir plus, consultez la page Configuration de test simple.
Fichier de configuration complexe
Pour les tests plus complexes, vous devez également écrire un fichier de configuration de test pour le banc d'essais d'Android, Trade Federation.
La configuration de test peut spécifier des options de configuration d'appareil spéciales et des arguments par défaut pour fournir la classe de test.
Vous pouvez accéder à la dernière version du fichier de configuration de l'exemple de modification Gerrit à l'adresse : frameworks/base/packages/Shell/tests/AndroidTest.xml.
Pour plus de commodité, un instantané est inclus:
<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>
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 le fichier ShellTests.apk sur l'appareil cible à l'aide d'un target_preparer spécifié. De nombreux préparateurs de 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 des tests.
<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>
Ce champ spécifie la classe de test de la fédération commerciale à utiliser pour exécuter le test et transmet le package sur l'appareil à exécuter, ainsi que le framework du lanceur de test, qui est JUnit dans ce cas.
Pour en savoir plus sur les configurations de module de test, consultez cette page.
Fonctionnalités de JUnit4
L'utilisation de la bibliothèque android-support-test
en tant qu'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.
Vous pouvez accéder au dernier code source de l'exemple de modification Gerrit à l'adresse : 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 certains modèles d'utilisation généralement utiles.
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {
Une différence importante dans JUnit4 est que les tests ne sont plus tenus 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 des annotations 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 avant la classe de test, suppression post-test et suppression de la classe post-test : semblables aux méthodes setUp
et tearDown
dans JUnit4.
L'annotation Test
permet d'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 une configuration avant le test.
Bien que n'étant pas utilisé dans cet exemple, @After
est également utilisé pour le démontage 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 dans une classe de test, puis être supprimées. Notez que les méthodes de configuration et de démontage de portée de classe doivent être statiques.
Contrairement aux versions précédentes de JUnit, les méthodes de test ne doivent plus commencer 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 déclarer aucune valeur renvoyée, n'accepter aucun paramètre et pouvoir 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 des instances Context
via getContext()
ou getTargetContext()
via les méthodes de la classe de base. Au lieu de cela, le nouveau testeur les gère via InstrumentationRegistry
, où la configuration contextuelle et environnementale créée par le framework d'instrumentation est stockée. Vous pouvez également appeler les méthodes suivantes:
getInstrumentation()
: instance de la classeInstrumentation
getArguments()
: arguments de ligne de commande transmis àam instrument
via-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 importante, suivez les instructions d'instrumentation.