Google is committed to advancing racial equity for Black communities. See how.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Esempio di test TF end-to-end

Questo tutorial ti guida attraverso la creazione di una configurazione di prova della Trade Federation (TF) "hello world" e ti offre un'introduzione pratica al framework TF. Partendo da un ambiente di sviluppo, creerai una semplice configurazione e aggiungerai funzionalità.

Il tutorial presenta il processo di sviluppo del test come una serie di esercizi, ciascuno costituito da diversi passaggi, che dimostrano come creare e perfezionare gradualmente la configurazione. Viene fornito tutto il codice di esempio necessario per completare la configurazione del test e il titolo di ogni esercizio è annotato con una lettera che descrive i ruoli coinvolti in quella fase:

  • D per sviluppatore
  • Io per integratore
  • R per Test Runner

Dopo aver completato il tutorial, si avrà una configurazione TF funzionante e si comprenderanno molti concetti importanti nel framework TF.

Creazione della Federazione dei Mercanti

Per i dettagli sulla configurazione dell'ambiente di sviluppo TF, vedere Configurazione macchina . Il resto di questo tutorial presume che tu abbia una shell aperta che è stata inizializzata nell'ambiente TF.

Per semplicità, questo tutorial illustra l'aggiunta di una configurazione e delle sue classi alla libreria principale del framework TF. Questo può essere esteso allo sviluppo di moduli al di fuori dell'albero dei sorgenti compilando il JAR scambiato, quindi compilando i moduli con quel JAR.

Creazione di una classe di test (D)

Creiamo un hello world test che scarichi semplicemente un messaggio su stdout. Un test tradefed generalmente implementa l'interfaccia IRemoteTest . Ecco un'implementazione per HelloWorldTest:

package com.android.tradefed.example;

import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.testtype.IRemoteTest;

public class HelloWorldTest implements IRemoteTest {
    @Override
    public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException {
        CLog.i("Hello, TF World!");
    }
}

Salva questo codice di esempio in <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java e ricostruisci tradefed dalla tua shell:

m -jN

Notare che CLog.i nell'esempio precedente viene utilizzato per indirizzare l'output alla console. Ulteriori informazioni sull'accesso a Trade Federation sono descritte in Registrazione (D, I, R) .

Se la compilazione non riesce, consultare Configurazione macchina per assicurarsi di non aver perso un passaggio.

Creazione di una configurazione (I)

I test di Trade Federation vengono resi eseguibili creando una configurazione , un file XML che indica a TradeFed su quale test (o test) eseguire, nonché su quali altri moduli eseguire e in quale ordine.

Consente di creare una nuova configurazione per il nostro HelloWorldTest (notare il nome completo della classe di HelloWorldTest):

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
</configuration>

Salva questi dati in un file helloworld.xml ovunque sul tuo filesystem locale (ad esempio /tmp/helloworld.xml ). TF analizzerà il file XML di configurazione (noto anche come config ), caricherà la classe specificata usando la reflection, la IRemoteTest , la IRemoteTest un IRemoteTest e chiamerà il suo metodo di run .

Esecuzione della configurazione (R)

Dalla shell, avvia la console tradefed:

tradefed.sh

Assicurati che un dispositivo sia connesso alla macchina host e sia visibile a tradefed:

tf> list devices
Serial            State      Product   Variant   Build   Battery
004ad9880810a548  Available  mako      mako      JDQ39   100

Le configurazioni possono essere eseguite utilizzando il comando da console run <config> . Provare:

tf> run /tmp/helloworld.xml
05-12 13:19:36 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548
Hello, TF World!

Dovresti vedere "Hello, TF World!" uscita sul terminale.

È possibile confermare che un comando è stato eseguito utilizzando le list invocations o li nel prompt della console e non dovrebbe stampare nulla. Se i comandi sono attualmente in esecuzione, vengono visualizzati come segue:

tf >l i
Command Id  Exec Time  Device       State
10          0m:00      [876X00GNG]  running stub on build(s) 'BuildInfo{bid=0, target=stub, serial=876X00GNG}'

Aggiunta della configurazione al classpath (D, I, R)

Per comodità di distribuzione, puoi anche raggruppare le configurazioni negli stessi JAR scambiati. Tradefed riconosce automaticamente tutte le configurazioni inserite nelle cartelle di configurazione sul classpath.

Per illustrare, sposta il file helloworld.xml nella libreria principale tradefed ( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml ). Ricostruisci tradefed, riavvia la console tradefed, quindi chiedi a tradefed di visualizzare l'elenco delle configurazioni dal classpath:

tf> list configs
[…]
example/helloworld: Runs the hello world test

Ora puoi eseguire la configurazione di helloworld usando:

tf> run example/helloworld
05-12 13:21:21 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548
Hello, TF World!

Interagire con un dispositivo (D, R)

Finora, il nostro HelloWorldTest non sta facendo nulla di interessante. La specialità di Tradefed è l'esecuzione di test utilizzando dispositivi Android, quindi aggiungiamo un dispositivo Android al test.

I test possono ottenere un riferimento a un dispositivo Android usando TestInformation , fornito dal framework quando viene chiamato il metodo IRemoteTest#run .

Modifichiamo il messaggio di stampa HelloWorldTest per visualizzare il numero di serie del dispositivo:

@Override
public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException {
    CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber());
}

Ora ricostruisci tradefed e controlla l'elenco dei dispositivi:

tradefed.sh
tf> list devices
Serial            State      Product   Variant   Build   Battery
004ad9880810a548  Available  mako      mako      JDQ39   100

Prendere nota del numero di serie elencato come Disponibile ; questo è il dispositivo che dovrebbe essere assegnato a HelloWorld:

tf> run example/helloworld
05-12 13:26:18 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548
Hello, TF World! I have device 004ad9880810a548

Dovresti vedere il nuovo messaggio di stampa che mostra il numero di serie del dispositivo.

Invio dei risultati del test (D)

IRemoteTest riporta i risultati chiamando i metodi sull'istanza ITestInvocationListener fornita al metodo #run . Lo stesso framework TF è responsabile della segnalazione dell'inizio (tramite ITestInvocationListener # invocationStarted ) e della fine (tramite ITestInvocationListener # invocationEnded ) di ciascuna chiamata.

Un'esecuzione di test è una raccolta logica di test. Per riportare i risultati del test, IRemoteTest è responsabile della segnalazione dell'inizio di una corsa di prova, l'inizio e la fine di ogni prova e la fine della corsa di prova.

Ecco come potrebbe apparire l'implementazione HelloWorldTest con un singolo risultato di test non riuscito.

@Override
public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException {
    CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber());

    TestDescription testId = new TestDescription("com.example.TestClassName", "sampleTest");
    listener.testRunStarted("helloworldrun", 1);
    listener.testStarted(testId);
    listener.testFailed(testId, "oh noes, test failed");
    listener.testEnded(testId, Collections.emptyMap());
    listener.testRunEnded(0, Collections.emptyMap());
}

TF include diverse implementazioni di IRemoteTest che puoi riutilizzare invece di scrivere le tue da zero. Ad esempio, InstrumentationTest può eseguire i test di un'applicazione Android in remoto su un dispositivo Android, analizzare i risultati e inoltrarli a ITestInvocationListener ). Per i dettagli, vedere Tipi di test .

Memorizzazione dei risultati dei test (I)

L'implementazione del listener di test predefinito per una configurazione TF è TextResultReporter , che scarica i risultati di una chiamata su stdout. Per illustrare, eseguire la configurazione HelloWorldTest dalla sezione precedente:

./tradefed.sh
tf> run example/helloworld
04-29 18:25:55 I/TestInvocation: Invocation was started with cmd: /tmp/helloworld.xml
04-29 18:25:55 I/TestInvocation: Starting invocation for 'stub' with '[ BuildInfo{bid=0, target=stub, serial=876X00GNG} on device '876X00GNG']
04-29 18:25:55 I/HelloWorldTest: Hello, TF World! I have device 876X00GNG
04-29 18:25:55 I/InvocationToJUnitResultForwarder: Running helloworldrun: 1 tests
04-29 18:25:55 W/InvocationToJUnitResultForwarder:
Test com.example.TestClassName#sampleTest failed with stack:
 oh noes, test failed
04-29 18:25:55 I/InvocationToJUnitResultForwarder: Run ended in 0 ms

Per memorizzare i risultati di una chiamata altrove, ad esempio in un file, specificare un'implementazione ITestInvocationListener personalizzata utilizzando il tag result_reporter nella configurazione.

TF include anche il listener XmlResultReporter , che scrive i risultati del test in un file XML in un formato simile a quello utilizzato dal writer XML di ant JUnit. Per specificare il result_reporter nella configurazione, modifica la configurazione …/res/config/example/helloworld.xml :

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
    <result_reporter class="com.android.tradefed.result.XmlResultReporter" />
</configuration>

Ora ricostruisci tradefed e riesegui il campione hello world:

tf> run example/helloworld
05-16 21:07:07 I/TestInvocation: Starting invocation for target stub on build 0 on device 004ad9880810a548
Hello, TF World! I have device 004ad9880810a548
05-16 21:07:07 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_2991649128735283633/device_logcat_6999997036887173857.txt
05-16 21:07:07 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_2991649128735283633/host_log_6307746032218561704.txt
05-16 21:07:07 I/XmlResultReporter: XML test result file generated at /tmp/0/inv_2991649128735283633/test_result_536358148261684076.xml. Total tests 1, Failed 1, Error 0

Notare il messaggio di registro che indica che è stato generato un file XML; il file generato dovrebbe essere simile a questo:

<?xml version='1.0' encoding='UTF-8' ?>
<testsuite name="stub" tests="1" failures="1" errors="0" time="9" timestamp="2011-05-17T04:07:07" hostname="localhost">
  <properties />
  <testcase name="sampleTest" classname="com.example.TestClassName" time="0">
    <failure>oh noes, test failed
    </failure>
  </testcase>
</testsuite>

È inoltre possibile scrivere i propri listener di invocazione personalizzati, che devono semplicemente implementare l'interfaccia ITestInvocationListener .

Tradefed supporta più listener di invocazione, quindi puoi inviare i risultati dei test a più destinazioni indipendenti. Per fare ciò, specifica più tag <result_reporter> nella tua configurazione.

Registrazione (D, I, R)

Le strutture di registrazione di TF includono la capacità di:

  1. Cattura i registri dal dispositivo (noto anche come dispositivo logcat)
  2. Registra i log dal framework Trade Federation in esecuzione sulla macchina host (noto anche come log host)

Il framework TF acquisisce automaticamente il logcat dal dispositivo allocato e lo invia al listener di invocazione per l'elaborazione. XmlResultReporter salva quindi il logcat del dispositivo acquisito come file.

I log dell'host TF vengono riportati utilizzando il wrapper CLog per la classe Log ddmlib. Convertiamo la precedente chiamata System.out.println in HelloWorldTest in una chiamata CLog :

@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    CLog.i("Hello, TF World! I have device %s", getDevice().getSerialNumber());

CLog gestisce direttamente l'interpolazione delle stringhe, in modo simile a String.format . Quando ricostruisci e riesegui TF, dovresti vedere il messaggio di log su stdout:

tf> run example/helloworld
…
05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
…

Per impostazione predefinita, tradefed restituisce messaggi di log host a stdout . TF include anche un'implementazione del log che scrive i messaggi in un file: FileLogger . Per aggiungere la registrazione dei file, aggiungi un tag logger alla configurazione, specificando il nome completo della classe di FileLogger :

<configuration description="Runs the hello world test">
    <test class="com.android.tradefed.example.HelloWorldTest" />
    <result_reporter class="com.android.tradefed.result.XmlResultReporter" />
    <logger class="com.android.tradefed.log.FileLogger" />
</configuration>

Ora, ricostruisci ed esegui di nuovo l'esempio di helloworld:

tf >run example/helloworld
…
05-16 21:38:21 I/XmlResultReporter: Saved device_logcat log to /tmp/0/inv_6390011618174565918/device_logcat_1302097394309452308.txt
05-16 21:38:21 I/XmlResultReporter: Saved host_log log to /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
…

Il messaggio di registro indica il percorso del registro host, che, se visualizzato, dovrebbe contenere il messaggio di registro HelloWorldTest:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Output di esempio:

…
05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548

Opzioni di manipolazione (D, I, R)

Gli oggetti caricati da una configurazione TF ( @Option anche come oggetti di configurazione ) possono anche ricevere dati dagli argomenti della riga di comando tramite l'uso dell'annotazione @Option .

Per partecipare, una classe di oggetti Configuration applica l'annotazione @Option a un campo membro e gli fornisce un nome univoco. Ciò consente di popolare il valore del campo del membro tramite un'opzione della riga di comando (e aggiunge automaticamente tale opzione al sistema della guida alla configurazione).

Nota: non tutti i tipi di campo sono supportati. Per una descrizione dei tipi supportati, vedere OptionSetter .

Aggiungiamo una @Option a HelloWorldTest:

@Option(name="my_option",
        shortName='m',
        description="this is the option's help text",
        // always display this option in the default help text
        importance=Importance.ALWAYS)
private String mMyOption = "thisisthedefault";

Successivamente, aggiungiamo un messaggio di log per visualizzare il valore dell'opzione in HelloWorldTest in modo da poter dimostrare che è stato ricevuto correttamente:

@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    …
    CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);

Infine, ricostruisci TF ed esegui helloworld; dovresti vedere un messaggio di log con il valore predefinito my_option :

tf> run example/helloworld
…
05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'

Passaggio di valori dalla riga di comando

Passa un valore per my_option ; dovresti vedere my_option popolato con quel valore:

tf> run example/helloworld --my_option foo
…
05-24 18:33:44 I/HelloWorldTest: I received option 'foo'

Le configurazioni TF includono anche un sistema di guida, che visualizza automaticamente il testo della @Option per i campi @Option . Provalo ora e dovresti vedere il testo della my_option per my_option :

tf> run example/helloworld --help
Printing help for only the important options. To see help for all options, use the --help-all flag

  cmd_options options:
    --[no-]help          display the help text for the most important/critical options. Default: false.
    --[no-]help-all      display the full help text for all options. Default: false.
    --[no-]loop          keep running continuously. Default: false.

  test options:
    -m, --my_option      this is the option's help text Default: thisisthedefault.

  'file' logger options:
    --log-level-display  the minimum log level to display on stdout. Must be one of verbose, debug, info, warn, error, assert. Default: error.

Notare il messaggio relativo alla "stampa solo delle opzioni importanti". Per ridurre il disordine nella guida delle Option#importance , TF usa l'attributo di Option#importance per determinare se mostrare un particolare testo della @Option campo @Option quando --help è specificato. --help-all mostra sempre la guida per tutti i campi @Option , indipendentemente dall'importanza. Per i dettagli, vedere Option.Importance .

Passaggio di valori da una configurazione

Puoi anche specificare un valore Opzione all'interno della configurazione aggiungendo un elemento <option name="" value=""> . helloworld.xml usando helloworld.xml :

<test class="com.android.tradefed.example.HelloWorldTest" >
    <option name="my_option" value="fromxml" />
</test>

Ricostruire ed eseguire helloworld ora dovrebbe produrre questo output:

05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'

Anche la guida alla configurazione dovrebbe essere aggiornata per indicare il valore predefinito di my_option :

tf> run example/helloworld --help
  test options:
    -m, --my_option      this is the option's help text Default: fromxml.

Anche altri oggetti di configurazione inclusi nella configurazione di helloworld, come FileLogger , accettano opzioni. L'opzione --log-level-display è interessante perché filtra i log che vengono visualizzati su stdout. All'inizio del tutorial, potresti aver notato che il messaggio di log "Hello, TF World! Ho un dispositivo ..." smette di essere visualizzato su stdout dopo essere passati a utilizzare FileLogger . Puoi aumentare il livello di dettaglio del log in stdout passando il --log-level-display arg.

Prova ora e dovresti vedere il messaggio di registro "Ho dispositivo" riapparire su stdout, oltre a essere registrato in un file:

tf> run example/helloworld --log-level-display info
…
05-24 18:53:50 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548

È tutto gente!

Come promemoria, se sei bloccato su qualcosa, il codice sorgente della Federazione dei Mercanti contiene molte informazioni utili che non sono esposte nella documentazione. Se tutto il resto fallisce, prova a chiedere sulla piattaforma Android di Google Group, con "Trade Federation" nell'oggetto del messaggio.