Esempio di test TF end-to-end

Questo tutorial illustra la creazione di un "Hello World" Federazione commerciale (Tradefed or TF) e offre un'introduzione pratica a TF il modello di machine learning. Partendo da un ambiente di sviluppo, creerai una semplice configurazione e aggiungere funzionalità.

Il tutorial presenta il processo di sviluppo del test come una serie di esercizi, ciascuno costituito da diversi passaggi, che mostrano come creare e implementare per perfezionare la configurazione. Tutto il codice campione necessario per completare il test configurazione iniziale e il titolo di ogni esercizio è annotato con lettera che descrive i ruoli coinvolti in questa fase:

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

Dopo aver completato il tutorial, avrai una configurazione TF funzionante e di comprendere molti concetti importanti nel framework di TF.

Configura Trade Federation

Per maggiori dettagli sulla configurazione dell'ambiente di sviluppo TF, vedi Macchina Configurazione. Il resto del tutorial presuppone che tu abbia una shell aperta inizializzato nell'ambiente TF.

Per semplicità, questo tutorial illustra l'aggiunta di una configurazione e delle relative alla libreria di base del framework TF. Questo può essere esteso allo sviluppo moduli esterni all'albero di origine mediante la compilazione del JAR traslato, quindi la compilazione dei moduli rispetto al JAR.

Crea una classe di prova (D)

Creiamo un test Hello World che si limita a eseguire il dump di un messaggio su stdout. R tradefed test implementa generalmente Testa remota a riga di comando. Di seguito è riportata 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 campione in <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java e ricrearla traslata dalla tua shell:

m -jN

Tieni presente che CLog.i nell'esempio precedente viene utilizzato per indirizzare l'output alla console. Altro le informazioni sul logging nella Federazione commerciale sono descritte in Logging (D, I, R).

Se la creazione non riesce, consulta una Macchina per assicurarti di non perdere un passaggio.

Crea una configurazione (I)

I test della Trade Federation vengono resi eseguibili creando un Configuration, un file XML che fornisce istruzioni su quale test (o test) da eseguire, nonché quali altri moduli eseguire e in quale ordine.

Creiamo una nuova configurazione per il nostro HelloWorldTest (vedi il corso completo) nome 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 in qualsiasi punto della tua rete locale file system (ad es. /tmp/helloworld.xml). TF analizzerà Il file XML di configurazione (noto anche come config), carica la classe specificata utilizzando riflessione, creare un'istanza, trasmetterla a IRemoteTest e richiamare il suo run.

Esegui la configurazione (R)

Avvia la console trasferita dalla tua shell:

tradefed.sh

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

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

Le configurazioni possono essere eseguite utilizzando run <config> nella console Google Cloud. Prova:

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 il messaggio "Hello, TF World!". l'output sul terminale.

Puoi verificare che un comando sia stato eseguito utilizzando list invocations oppure l i nel messaggio della console e non dovrebbe essere stampato nulla. Se al momento i comandi sono 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}'

Aggiungi la configurazione al classpath (D, I, R)

Per maggiore praticità, puoi anche raggruppare le configurazioni I JAR stessi. Tradefed riconosce automaticamente tutte le configurazioni inserite config sulla classe.

Per spiegarci meglio, sposta il file helloworld.xml nel file convertito libreria di base (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml). Ricostruisci tradef tramite, riavvia la console tradefed, quindi chiedi tradefed per visualizzare il elenco di configurazioni da classpath:

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

Ora puoi eseguire la configurazione di helloworld utilizzando:

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)

Al momento, il nostro HelloWorldTest non ha dato risultati interessanti. Tradefed è l'esecuzione di test con dispositivi Android, quindi aggiungiamo un dispositivo Android al test.

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

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

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

Ora puoi ricreare la trasferta e controllare l'elenco dei dispositivi:

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

Prendi nota del numero di serie indicato come Available. ovvero il dispositivo che deve essere allocato 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.

Invia risultati test (D)

IRemoteTest restituisce i risultati richiamando metodi sul ITestInvocationListener fornita al metodo #run. Il framework TF stesso responsabile di segnalare l'inizio (tramite ITestInvocationListener#invocationStarted) e alla fine (tramite ITestInvocationListener#invocationEnded) di ogni chiamata.

Un'esecuzione di test è una raccolta logica di test. Per segnalare i risultati del test, IRemoteTest è responsabile di segnalare l'inizio di un'esecuzione di test, l'inizio e la fine di ogni test e la fine dell'esecuzione del test.

Ecco come potrebbe presentarsi l'implementazione HelloWorldTest con una singola risultato del test non superato.

@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 IRemoteTest che puoi riutilizzare anziché scriverne uno tutto tuo da zero. Ad esempio: Test di strumentazione eseguire i test di un'applicazione Android da remoto su un dispositivo Android, analizzare risultati e inoltrali al team ITestInvocationListener). Per maggiori dettagli, vedi Prova Tipi.

Archivia i risultati del test (I)

L'implementazione predefinita del listener di test per una configurazione TF è TextResultReporter che scarica i risultati di una chiamata a stdout. Per illustrare il concetto, esegui il comando Configurazione di HelloWorldTest della 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 archiviare i risultati di una chiamata altrove, ad esempio in un file, specifica implementazione personalizzata di ITestInvocationListener utilizzando result_reporter nella tua configurazione.

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

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

Ora ricrea la trasferta ed esegui di nuovo l'esempio di 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

Osserva il messaggio di log che indica che è stato generato un file XML. il generato dovrebbe avere il seguente aspetto:

<?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>

Puoi anche scrivere listener di chiamata personalizzati, semplicemente devi implementare ITestInvocationListener a riga di comando.

Tradefed supporta più listener di chiamate, quindi puoi inviare i risultati del test verso più destinazioni indipendenti. Per farlo, è sufficiente specificare più <result_reporter> tag nella configurazione.

Impianti di lavorazione forestale (D, I, R)

Le strutture di registrazione di TF offrono la possibilità di:

  1. Acquisire i log dal dispositivo (noto anche come logcat del dispositivo)
  2. Registra i log dal framework della Trade Federation in esecuzione sul computer host (noto anche come log host)

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

I log host TF vengono segnalati utilizzando Wrapper CLog per la classe ddmlib Log. Convertiamo precedente chiamata System.out.println in HelloWorldTest a un 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 di stringhe, come String.format. Quando ricrei ed esegui di nuovo TF, dovresti vedere 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, log host di output a stdout. TF include anche un'implementazione di log che scrive messaggi in un file: FileLogger. Per aggiungere il logging dei file, aggiungi un tag logger alla configurazione, specificando il nome completo della classe 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 ricrea 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 log indica il percorso del log dell'host che, quando visualizzato, deve contenere il messaggio di log 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 gestione (D, I, R)

Oggetti caricati da una configurazione TF (noti anche come oggetti di configurazione) può anche ricevere dati da argomenti della riga di comando utilizzando annotazione @Option.

Per partecipare, una classe di oggetti Configurazione applica @Option a un campo membro e gli assegna un nome univoco. Ciò consente il valore del campo membro da compilare tramite un'opzione della riga di comando (e anche l'opzione viene aggiunta automaticamente al sistema di assistenza per la configurazione).

Nota: non tutti i tipi di campo sono supportati. Per un la descrizione dei tipi supportati, consulta OptionSetter.

Aggiungiamo @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";

Quindi, aggiungiamo un messaggio di log per visualizzare il valore dell'opzione HelloWorldTest per consentirci di dimostrare che è stato ricevuto correttamente:

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

Infine, ricrea TF ed esegui helloworld; dovresti vedere un messaggio di log con Valore predefinito my_option:

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

Trasmettere valori dalla riga di comando

Trasmetti un valore per my_option; dovresti vedere my_option compilato con questo 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 testo della guida per i campi @Option. Prova subito; dovresti vedere lo testo della guida 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.

Annota il messaggio sulla "stampa solo delle opzioni importanti". Per ridurre aiuta a creare confusione, TF usa l'attributo Option#importance per determinare se mostrare un determinato testo della guida del campo @Option quando --help è specificato. --help-all mostra sempre la guida per tutti i @Option campi, indipendentemente dall'importanza. Per maggiori dettagli, vedi Option.Importance (Opzione.Importanza).

Trasmettere valori da una configurazione

Puoi anche specificare un valore di opzione all'interno della configurazione aggiungendo Elemento <option name="" value="">. Esegui un test utilizzando helloworld.xml:

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

La ricreazione ed esecuzione di helloworld dovrebbe ora produrre questo output:

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

Anche la guida di configurazione dovrebbe aggiornarsi per indicare il valore predefinito my_option:

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

Altri oggetti di configurazione inclusi nella configurazione di helloworld, ad esempio FileLogger, accetta anche opzioni. L'opzione --log-level-display è interessante perché filtra i log che vengono visualizzati su stdout. In precedenza, nel tutorial, potresti aver notato la Mondo! Ho il dispositivo..." il messaggio di log non viene più visualizzato su stdout dopo che è passata all'utilizzo di FileLogger. Puoi aumentare il livello di dettaglio logging a stdout passando l'argomento --log-level-display.

Prova ora; dovresti vedere il messaggio "Ho il dispositivo" il messaggio di log riapparirà 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!

Ricorda che, se sei bloccato su qualcosa, Commercio Il codice sorgente della federazione contiene molte informazioni utili che non sono esposte nei la documentazione. Se il problema persiste, prova a chiedere nella piattaforma-android Gruppo Google, con "Trade Federation" nell'oggetto del messaggio.