Questa categoria di test di instrumentazione non è molto diversa da quelle che hanno come target le normali applicazioni Android. È importante notare che l'applicazione di test che includeva la strumentazione deve essere firmata con lo stesso certificato dell'applicazione di destinazione.
Tieni presente che questa guida presuppone che tu abbia già una certa conoscenza del flusso di lavoro dell'albero delle origini della piattaforma. In caso contrario, consulta la sezione Requisiti. L'esempio trattato qui riguarda la scrittura di un nuovo test di strumentazione con il pacchetto target impostato sul proprio pacchetto dell'applicazione di test. Se non hai familiarità con il concetto, leggi l'introduzione ai test della piattaforma.
Questa guida utilizza il seguente test come esempio:
- frameworks/base/packages/Shell/tests
Ti consigliamo di sfogliare prima il codice per farti un'idea generale prima di procedere.
Scegliere una posizione di origine
Poiché il test di strumentazione ha come target un'applicazione, la convenzione
prevede di inserire il codice sorgente del test in una directory tests
sotto la radice della
directory di origine del componente nell'albero delle origini della piattaforma.
Per ulteriori discussioni sulla posizione dell'origine, consulta l'esempio end-to-end per test di autostrumentazione.
File manifest
Come una normale applicazione, ogni modulo di test di strumentazione necessita di un file manifest. Se assegni al file il nome AndroidManifest.xml
e lo fornisci accanto a Android.mk
per il modulo di test, verrà incluso automaticamente nel makefile principale BUILD_PACKAGE
.
Prima di procedere, ti consigliamo vivamente di leggere la Panoramica del manifest dell'app.
Questa sezione fornisce una panoramica dei componenti di base di un file manifest e delle relative funzionalità.
È possibile accedere all'ultima versione del file manifest per la modifica di Gerrit di esempio all'indirizzo: https://android.googlesource.com/platform/frameworks/base/+/android16-release/packages/Shell/tests/AndroidManifest.xml
Per comodità, è incluso uno snapshot:
<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>
Alcuni commenti selezionati sul file manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.shell.tests">
L'attributo package
è il nome del pacchetto dell'applicazione: si tratta dell'identificatore univoco che il framework dell'applicazione Android utilizza per identificare un'applicazione (o, in questo contesto, la tua applicazione di test). Ogni utente del sistema
può installare una sola applicazione con quel nome del pacchetto.
Poiché si tratta di un pacchetto di test dell'applicazione, indipendente dal pacchetto dell'applicazione in fase di test, è necessario utilizzare un nome di pacchetto diverso: una convenzione comune è quella di aggiungere il suffisso .test
.
Inoltre, questo attributo package
è uguale a quello restituito da
ComponentName#getPackageName()
ed è lo stesso che utilizzeresti per interagire con vari sottocomandi pm
tramite adb shell
.
Tieni inoltre presente che, sebbene il nome del pacchetto abbia in genere lo stesso stile di un nome di pacchetto Java, in realtà ha ben poco a che fare con quest'ultimo. In altre parole, il pacchetto dell'applicazione (o del test) può contenere classi con qualsiasi nome del pacchetto, anche se, d'altra parte, potresti optare per la semplicità e avere il nome del pacchetto Java di primo livello nell'applicazione o nel test identico al nome del pacchetto dell'applicazione.
<uses-library android:name="android.test.runner" />
Questo è necessario per tutti i test di strumentazione, poiché le classi correlate sono inserite in un file JAR della libreria del framework separato, pertanto richiedono voci classpath aggiuntive quando il pacchetto di test viene richiamato dal framework dell'applicazione.
android:targetPackage="com.android.shell"
In questo modo, il pacchetto target dello strumento viene impostato su com.android.shell
.
Quando la strumentazione viene richiamata tramite il comando am instrument
, il framework
riavvia il processo com.android.shell
e inserisce il codice di strumentazione nel
processo per l'esecuzione del test. Ciò significa anche che il codice di test avrà
accesso a tutte le istanze di classe in esecuzione nell'applicazione in fase di test e potrebbe
essere in grado di manipolare lo stato a seconda degli hook di test esposti.
File di configurazione semplice
Ogni nuovo modulo di test deve avere un file di configurazione per indirizzare il sistema di compilazione con metadati del modulo, dipendenze in fase di compilazione e istruzioni di packaging. Nella maggior parte dei casi, l'opzione di file Blueprint basata su Soong è sufficiente. Per maggiori dettagli, consulta Configurazione semplice del test.
File di configurazione complesso
Per test più complessi, devi anche scrivere un file di configurazione di test per lo strumento di test di Android, Trade Federation.
La configurazione del test può specificare opzioni speciali di configurazione del dispositivo e argomenti predefiniti per fornire la classe di test.
È possibile accedere all'ultima versione del file di configurazione per la modifica di esempio di Gerrit all'indirizzo: frameworks/base/packages/Shell/tests/AndroidTest.xml
Per comodità, è incluso uno snapshot:
<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>
Alcuni commenti selezionati sul file di configurazione del test:
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="ShellTests.apk"/>
</target_preparer>
Indica a Trade Federation di installare ShellTests.apk sul dispositivo di destinazione utilizzando un target_preparer specificato. In Trade Federation sono disponibili molti preparatori di target e possono essere utilizzati per garantire che il dispositivo sia configurato correttamente prima dell'esecuzione del 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>
Specifica la classe di test Trade Federation da utilizzare per eseguire il test e passa il pacchetto sul dispositivo da eseguire e il framework di esecuzione dei test che in questo caso è JUnit.
Per ulteriori informazioni su Test Module Configs, consulta questa pagina.
Funzionalità di JUnit4
L'utilizzo della libreria android-support-test
come test runner consente l'adozione di nuove
classi di test in stile JUnit4 e la modifica di Gerrit di esempio contiene alcuni utilizzi molto basilari
delle sue funzionalità.
Il codice sorgente più recente per la modifica di esempio di Gerrit è disponibile all'indirizzo: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
Sebbene i pattern di test siano in genere specifici per i team dei componenti, esistono alcuni pattern di utilizzo generalmente utili.
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {
Una differenza significativa in JUnit4 è che i test non devono più ereditare da una classe di test di base comune; al contrario, scrivi i test in classi Java semplici e utilizza le annotazioni per indicare determinate configurazioni e vincoli dei test. In questo esempio, stiamo indicando che questa classe deve essere eseguita come test Android JUnit4.
L'annotazione @SmallTest
ha specificato una dimensione del test per l'intera classe di test: tutti i metodi di test aggiunti a questa classe di test ereditano questa annotazione della dimensione del test.
Configurazione pre-test della classe, eliminazione post-test e eliminazione post-test della classe:
simili ai metodi setUp
e tearDown
in JUnit4.
L'annotazione Test
viene utilizzata per annotare il test vero e proprio.
@Before
public void setup() {
...
@Test
public void testGetProvider_shouldCacheProvider() {
...
L'annotazione @Before
viene utilizzata sui metodi da JUnit4 per eseguire la configurazione pre-test.
Sebbene non venga utilizzato in questo esempio, esiste anche @After
per lo smontaggio post-test.
Analogamente, le annotazioni @BeforeClass
e @AfterClass
possono essere utilizzate
sui metodi di JUnit4 per eseguire la configurazione prima di eseguire tutti i test in una classe di test
e la pulizia successiva. Tieni presente che i metodi di configurazione e smontaggio
dell'ambito della classe devono essere statici.
Per quanto riguarda i metodi di test, a differenza delle versioni precedenti di JUnit, non è più necessario
iniziare il nome del metodo con test
, ma ognuno di essi deve essere annotato
con @Test
. Come di consueto, i metodi di test devono essere pubblici, non dichiarare alcun valore restituito,
non accettare parametri e possono generare eccezioni.
Context context = InstrumentationRegistry.getTargetContext();
Poiché i test JUnit4 non richiedono più una classe base comune, non è più
necessario ottenere istanze Context
tramite getContext()
o
getTargetContext()
tramite i metodi della classe base; al contrario, il nuovo test runner
le gestisce tramite InstrumentationRegistry
dove sono archiviate la configurazione contestuale e ambientale creata dal framework di strumentazione. Con questo corso puoi anche chiamare:
getInstrumentation()
: l'istanza della classeInstrumentation
getArguments()
: gli argomenti della riga di comando passati aam instrument
tramite-e <key> <value>
Creare build e testare in locale
Per i casi d'uso più comuni, utilizza Atest.
Per i casi più complessi che richiedono una personalizzazione più approfondita, segui le istruzioni di strumentazione.