Esempio di test di auto-strumentazione

Quando viene avviato un test di strumentazione, il relativo pacchetto target viene riavviata con codice di strumentazione inserito e avviato per l'esecuzione. Uno. è che il pacchetto di destinazione non può essere l'applicazione Android ad esempio il pacchetto android, perché in tal modo viene generato situazione paradossale in cui occorre riavviare il framework Android, che è ciò che supporta le funzioni di sistema, inclusa la strumentazione stessa.

Ciò significa che un test di strumentazione non può iniettarsi nel framework Android, noto anche come server di sistema, per l'esecuzione. Per testare Android framework, il codice di test può richiamare solo le piattaforme API pubbliche o quelle esposte con Android Interface Definition Language (DDL) AIDL disponibili nell'albero di origine della piattaforma. Per questa categoria di test, non è significativo come target un pacchetto specifico. Pertanto, è consuetudine di strumentazione da dichiarare per avere come target il proprio pacchetto di applicazioni di test, definita nel proprio tag <manifest> di AndroidManifest.xml.

A seconda dei requisiti, i pacchetti di applicazioni di test di questa categoria potrebbero inoltre:

  • Raggruppa le attività necessarie per i test.
  • Condividi lo User-ID con il sistema.
  • Essere firmate con la chiave della piattaforma.
  • Essere compilato in base al codice sorgente del framework anziché all'SDK pubblico.

Questa categoria di test di strumentazione è a volte indicata come l'autostrumentazione. Ecco alcuni esempi di test di autostrumentazione in dall'origine della piattaforma:

L'esempio illustrato qui è la scrittura di un nuovo test di strumentazione con target nel proprio pacchetto di applicazioni di test. Questa guida utilizza i seguenti come esempio:

Ti consigliamo di esaminare prima il codice per ottenere un'impressione approssimativa prima di procedere.

Scegli una posizione di origine

In genere il team ha già una serie di posti in cui effettuare i controlli nel codice e posizioni in cui aggiungere i test. La maggior parte dei team possiede un unico repository Git condividerne una con altri team, ma avere una sottodirectory dedicata che contiene il codice sorgente del componente.

Supponendo che la posizione principale dell'origine del componente sia in <component source root>, la maggior parte dei componenti ha src e tests cartelle al di sotto e alcune file aggiuntivi come Android.mk (o suddivisi in .mk file aggiuntivi), il file manifest AndroidManifest.xml e il file di configurazione di test "AndroidTest.xml".

Dato che stai aggiungendo un nuovo test, probabilmente dovrai creare il tests accanto al componente src e compilala con dei contenuti.

In alcuni casi, il team potrebbe avere ulteriori strutture di directory in tests per la necessità di pacchettizzare diverse suite di test in singoli apk. e in questo caso dovrai creare una nuova directory secondaria in tests.

Indipendentemente dalla struttura, finirai per compilare la directory tests o la sottodirectory appena creata con file simili a quelli contenuti nella directory instrumentation nella modifica di gerrit di esempio. I dettagli di ogni vengono spiegati più avanti in questo documento.

File manifest

Come per un progetto dell'app, ogni modulo di test della strumentazione richiede un file manifest denominato AndroidManifest.xml. Per includere automaticamente questo file utilizzando il BUILD_PACKAGE makefile principale, fornisci questo file accanto Android.mk per il modulo di test.

Se non hai dimestichezza con il file AndroidManifest.xml, consulta la Panoramica del file manifest dell'app.

Di seguito è riportato un file AndroidManifest.xml di esempio:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

Alcune note selezionate sul file manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

L'attributo package è il nome del pacchetto dell'applicazione: si tratta dell'identificatore univoco utilizzato dal framework di applicazioni Android per identificare un'applicazione (o, in questo contesto, la tua applicazione di test). Ogni utente nel sistema può installare una sola applicazione con quel nome pacchetto.

Inoltre, questo attributo package è uguale a ComponentName#getPackageName() e lo stesso che utilizzeresti per interagire con i vari pm usano adb shell.

Tieni presente che, anche se il nome del pacchetto è in genere nello stesso stile di un nome del pacchetto Java, in realtà non ha molto a che fare con esso. In altre parole, il pacchetto dell'applicazione (o del test) può contenere classi con qualsiasi nome del pacchetto, anche se, d'altra parte, puoi 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.

android:sharedUserId="android.uid.system"

Dichiara che al momento dell'installazione a questo file APK deve essere concesso lo stesso ID utente, ovvero l'identità di runtime, della piattaforma di base. Tieni presente che dipende dall'APK firmato con lo stesso certificato della piattaforma di base. (vedi LOCAL_CERTIFICATE in una sezione precedente), ma sono diversi di base:

  • alcune autorizzazioni o API sono protette da firma, il che richiede certificato di firma
  • alcune autorizzazioni o API richiedono l'identità system del chiamante, che richiede che il pacchetto chiamante condivida l'ID utente con system, se si tratta di un un pacchetto separato dalla piattaforma di base
<uses-library android:name="android.test.runner" />

Questo passaggio è obbligatorio per tutti i test di strumentazione poiché le classi correlate sono pacchettizzati in un file di libreria JAR separato, pertanto richiede Voci classpath quando il pacchetto di test viene richiamato dal framework dell'applicazione.

android:targetPackage="android.test.example.helloworld"

Potresti aver notato che il valore targetPackage qui viene dichiarato uguale al Attributo package dichiarato nel tag manifest di questo file. Come menzionato in nozioni di base sui test, questa categoria di test di strumentazione è in genere destinata a testare le API del framework, quindi non è molto significativa uno specifico pacchetto dell'applicazione target, diverso da quello stesso.

File di configurazione semplice

Ogni nuovo modulo di test deve avere un file di configurazione per indirizzare il sistema di compilazione con metadati dei moduli, dipendenze del tempo di compilazione e pacchetti istruzioni. Nella maggior parte dei casi, l'opzione File Blueprint basato su Presto è sufficienti. Per maggiori dettagli, vedi Configurazione di test semplice.

File di configurazione complesso

Per questi casi più complessi, devi anche scrivere un file di configurazione del test per la suite di test di Android, Trade Federation.

La configurazione del test può specificare opzioni di configurazione del dispositivo speciali e argomenti predefinite per fornire la classe di test. Vedi l'esempio alla pagina /platform_testing/tests/example/instrumentation/AndroidTest.xml.

Per comodità, è incluso uno snapshot:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

Alcune osservazioni specifiche sul file di configurazione del test:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

Questo indica alla Trade Federation di installare HelloWorldTests.apk sul target dispositivo utilizzando un valore target_preparer specificato. In Trade Federation sono disponibili molti preparatisti di target per gli sviluppatori, che possono essere utilizzati per assicurarsi che il dispositivo sia configurato correttamente prima dell'esecuzione del test.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Questo specifica la classe di test Trade Federation da utilizzare per eseguire il test e passa il pacchetto sul dispositivo da eseguire e il framework del programma di test, che in questo caso è JUnit.

Per ulteriori informazioni, vedi Configurazioni di moduli di test.

Funzionalità JUnit4

L'utilizzo della libreria android-support-test come test runner consente l'adozione di nuovi classi di test in stile JUnit4 e il cambio di gerrit di esempio contiene l'uso delle sue funzionalità. Vedi l'esempio alla pagina /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java.

Sebbene i pattern di test siano in genere specifici dei team dei componenti, ci sono alcune modelli di utilizzo generalmente utili.

@RunWith(JUnit4.class)
public class HelloWorldTest {

Una differenza significativa di JUnit4 è che i test non sono più tenuti a ereditare da una classe di test di base comune. Invece, scrivi i test in classi Java semplici e utilizzi le annotazioni per indicare determinate configurazioni e vincoli di test. Nel in questo esempio, indichiamo che questa classe deve essere eseguita come test JUnit4.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

Le annotazioni @Before e @After vengono utilizzate sui metodi di JUnit4 per eseguire configurazione pre-test e rimozione post-test. Analogamente, i @BeforeClass e Le annotazioni @AfterClass vengono utilizzate sui metodi di JUnit4 per eseguire la configurazione prima eseguendo tutti i test in una classe di test e poi all'eliminazione. Tieni presente che I metodi di configurazione e disinstallazione dell'ambito delle classi devono essere statici. Per quanto riguarda i metodi di test, a differenza della versione precedente di JUnit, non è più necessario iniziare il nome del metodo con test, invece, ognuna deve essere annotata con @Test. Come sempre, i metodi di test devono essere pubblici, dichiarare nessun valore restituito, non accettare parametri e potrebbero generare eccezioni.

Accesso alla classe di strumentazione

Sebbene non venga trattato nell'esempio di base di Hello World, è abbastanza comune Test Android per richiedere l'accesso all'istanza Instrumentation: questa è l'API principale interfaccia che fornisce accesso a contesti applicativi, ciclo di vita dell'attività API di test correlate e altro ancora.

Poiché i test JUnit4 non richiedono più una classe di base comune, non è più necessario ottenere un'istanza Instrumentation tramite InstrumentationTestCase#getInstrumentation(), ma il nuovo test runner la gestisce tramite InstrumentationRegistry, dove viene memorizzata la configurazione contestuale e ambientale creata dal framework di misurazione.

Per accedere all'istanza della classe Instrumentation, è sufficiente chiamare il metodo statico getInstrumentation() sulla classe InstrumentationRegistry:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Creazione e test in locale

Per i casi d'uso più comuni, utilizza Conferma.

Per i casi più complessi che richiedono una personalizzazione più intensa, segui le istruzioni sulla strumentazione.