Exemple de test TF de bout en bout

Ce tutoriel vous explique comment créer un "Hello World" Fédération du commerce (Tradefed ou TF) et d'une introduction pratique à TF d'infrastructure. À partir d'un environnement de développement, vous allez créer la configuration et ajouter des fonctionnalités.

Le tutoriel présente le processus de développement de tests sous la forme d'une série d'exercices, composées chacune de plusieurs étapes, qui montrent comment créer pour affiner votre configuration. Tous les exemples de code dont vous avez besoin pour effectuer le test est fournie, et le titre de chaque exercice est annoté lettre décrivant les rôles impliqués dans cette étape:

  • D pour "Développeur"
  • I (intégrateur)
  • R pour Test Runner

Une fois le tutoriel terminé, vous disposerez d'une configuration TF opérationnelle et comprendre de nombreux concepts importants du framework TF.

Configurer une fédération commerciale

Pour savoir comment configurer l'environnement de développement TF, consultez Machine Configuration. Dans la suite de ce tutoriel, nous partons du principe que vous disposez d'un shell ouvert qui a été initialisé dans l'environnement TF.

Par souci de simplicité, ce tutoriel explique comment ajouter une configuration et ses à la bibliothèque principale du framework TF. Cela peut s'étendre au développement en dehors de l'arborescence source en compilant le fichier JAR échangé, puis en compilant vos modules par rapport à ce fichier JAR.

Créer une classe de test (D)

Créons un test Hello World qui transfère simplement un message vers stdout. A le test tradefed implémente généralement IRemoteTest de commande. Voici une implémentation pour 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!");
    }
}

Enregistrez cet exemple de code dans <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java puis recompilez votre échange depuis votre shell:

m -jN

Notez que CLog.i dans l'exemple ci-dessus est utilisé pour diriger la sortie vers la console. Plus les informations relatives à la journalisation dans la fédération du commerce sont décrites dans la section Journalisation (D, I, R).

Si la compilation échoue, consultez Machine Configuration pour vous assurer de ne manquer aucune étape.

Créer une configuration (I)

Les tests de la fédération du commerce sont rendus exécutables en créant un Configuration : un fichier XML indiquant les données échangées (ou tests) à exécuter, ainsi que les autres modules à exécuter et dans quels cas commande.

Créons une configuration pour notre HelloWorldTest (notez que la classe complète de la classe HelloWorldTest):

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

Enregistrez ces données dans un fichier helloworld.xml sur votre disque local système de fichiers (par exemple, /tmp/helloworld.xml). TF analyse le paramètre Fichier XML de configuration (ou config), chargez la classe spécifiée en utilisant la réflexion, l'instancier, la caster en IRemoteTest et l'appeler run.

Exécuter la configuration (R)

À partir de votre shell, lancez la console tradefed:

tradefed.sh

Assurez-vous qu'un appareil est connecté à la machine hôte et qu'il est visible pour les échanges:

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

Les configurations peuvent être exécutées à l'aide de l'run <config> console. Conseil :

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!

Le message "Hello, TF World!" doit s'afficher. sur le terminal.

Vous pouvez vérifier qu'une commande est bien exécutée en utilisant list invocations ou l i dans l'invite de la console, et rien ne devrait s'afficher. Si les commandes sont actuellement en cours d'exécution, elles s'affichent comme suit:

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}'

Ajouter la configuration au chemin de classe (D, I, R)

Pour faciliter le déploiement, vous pouvez aussi regrouper les configurations dans des fichiers JAR eux-mêmes. Tradefed reconnaît automatiquement toutes les configurations placées dans config sur le chemin de classe.

Par exemple, déplacez le fichier helloworld.xml dans le fichier tradefed bibliothèque principale (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml). Reconstruisez la console échangée, redémarrez la console, puis demandez à tradefed d'afficher liste des configurations à partir du classpath:

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

Vous pouvez maintenant exécuter la configuration helloworld à l'aide de la commande suivante:

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!

Interagir avec un appareil (D, R)

Pour l'instant, HelloWorldTest ne fait rien d'intéressant. Tradefed's est d'effectuer des tests avec des appareils Android. à l'épreuve.

Les tests peuvent obtenir une référence à un appareil Android à l'aide de TestInformation, fourni par le framework lorsque la méthode IRemoteTest#run est appelée.

Modifions à présent le message d'impression HelloWorldTest pour afficher le numéro de série l'appareil:

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

À présent, recompilez votre échange et vérifiez la liste des appareils:

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

Notez le numéro de série indiqué comme Disponible. qui est l'appareil qui doit être alloué à 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

Le nouveau message d'impression indiquant le numéro de série du appareil.

Envoyer les résultats du test (D)

IRemoteTest signale les résultats en appelant des méthodes sur le Écouteur d'appels d'objets fournie à la méthode #run. Le framework TF lui-même responsable de la création de rapports sur les débuts (via ITestInvocationListener#invocationStarted) et à la fin (via ITestInvocationListener#invocationEnded) de chaque appel.

Une exécution de test est une collection logique de tests. Pour générer des rapports sur les résultats des tests, IRemoteTest permet de signaler le début de l'exécution d'un test. le début et la fin de chaque test, et la fin du test.

Voici à quoi pourrait ressembler l'implémentation de HelloWorldTest avec un seul échec du résultat du test.

@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 inclut plusieurs implémentations IRemoteTest que vous pouvez réutiliser au lieu d'écrire les vôtres à partir de zéro. Par exemple : Test d'instrumentation peut exécuter les tests d'une application Android à distance sur un appareil Android, analyser le et les transmettre au ITestInvocationListener). Pour en savoir plus, consultez Test Types.

Stocker les résultats des tests (I)

L'implémentation de l'écouteur de test par défaut pour une configuration TF est la suivante : TextResultReporter, qui vide les résultats d'un appel vers stdout. Par exemple, exécutez la commande Configuration HelloWorldTest de la section précédente:

./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

Pour stocker les résultats d'une invocation ailleurs, par exemple dans un fichier, spécifiez un une implémentation personnalisée de ITestInvocationListener à l'aide de Balise result_reporter dans votre configuration.

TF inclut également XmlResultReporter "Listener" qui écrit les résultats des tests dans un fichier XML dans un format semblable à celui-ci utilisé par le rédacteur XML ant JUnit. Pour spécifier le paramètre "result_reporter" dans modifier la configuration, modifiez …/res/config/example/helloworld.xml configuration:

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

À présent, recréez les données échangées et exécutez à nouveau l'exemple 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

Notez le message de journal indiquant qu'un fichier XML a été généré : la généré doit se présenter comme suit:

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

Vous pouvez également écrire vos propres écouteurs d'appel personnalisés. Ils vous n'avez pas besoin d'implémenter Écouteur d'appels d'API ITestInvocation de commande.

Tradefed accepte plusieurs écouteurs d'appel, ce qui vous permet d'envoyer les résultats des tests vers plusieurs destinations indépendantes. Pour ce faire, il vous suffit de spécifier plusieurs Balises <result_reporter> dans votre configuration.

Installations d'exploitation forestière (D, I, R)

Parmi les installations de journalisation de TensorFlow, on peut citer:

  1. Capturer les journaux de l'appareil (également appelé Logcat de l'appareil)
  2. Enregistrer des journaux à partir du framework de la fédération commerciale s'exécutant sur la machine hôte (également appelé "journal de l'hôte")

Le framework TF capture automatiquement le fichier logcat à partir de l'appareil alloué et l'envoie à l'écouteur d'appel pour traitement. XmlResultReporter enregistre ensuite le Logcat de l'appareil capturé en tant que fichier.

Les journaux de l'hôte TF sont signalés à l'aide du Wrapper de journalisation pour la classe Log ddmlib. Convertissons précédent appel System.out.println dans HelloWorldTest à une Appel CLog:

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

CLog gère directement l'interpolation de chaîne, comme pour String.format Lorsque vous recompilez et réexécutez TF, vous devez voir Message de journal sur stdout:

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

Par défaut, les données échangées sortie du journal de l'hôte des messages à stdout. TF inclut également une implémentation de journal qui écrit messages dans un fichier: FileLogger Pour ajouter la journalisation des fichiers, ajoutez une balise logger à la configuration, en spécifiant le Nom complet de 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>

Maintenant, recompilez et exécutez à nouveau l'exemple 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
…

Le message de journal indique le chemin du journal de l'hôte qui, une fois affiché, doit contenir votre message de journal HelloWorldTest:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Exemple de résultat :

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

Options de traitement (D, I, R)

Objets chargés à partir d'une configuration TF (également appelés objets de configuration) peut également recevoir des données à partir d'arguments de ligne de commande à l'aide du Annotation @Option.

Pour participer, une classe d'objet Configuration applique l'@Option à un champ de membre et lui attribue un nom unique. Cela permet valeur du champ membre à renseigner via une option de ligne de commande (et aussi ajoute automatiquement cette option au système d'aide à la configuration).

Remarque:Tous les types de champs ne sont pas acceptés. Pour une des types pris en charge, reportez-vous à OptionSetter :

Ajoutons un @Option à 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";

Ensuite, ajoutons un message de journal pour afficher la valeur de l'option dans HelloWorldTest afin de vérifier qu'il a bien été reçu:

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

Enfin, recompilez TF et exécutez helloworld. vous devriez voir un message de journal indiquant Valeur par défaut de my_option:

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

Transmettre des valeurs à partir de la ligne de commande

Transmettez une valeur pour my_option. vous devriez voir my_option renseigné avec cette valeur:

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

Les configurations TF incluent également un système d'aide qui affiche automatiquement Texte d'aide pour les champs @Option. Essayez maintenant. Vous devriez voir texte d'aide pour 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.

Notez le message "n'imprimer que les options importantes". Pour réduire une aide encombrante, TF utilise l'attribut Option#importance pour déterminer si un texte d'aide de champ @Option spécifique doit s'afficher --help est spécifié. --help-all affiche toujours de l'aide pour tous les champs @Option, quelle que soit leur importance. Pour en savoir plus, consultez Option.Importance :

Transmettre des valeurs à partir d'une configuration

Vous pouvez également spécifier une valeur "Option" dans la configuration en ajoutant un Élément <option name="" value="">. Testez-le avec helloworld.xml:

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

La reconstruction et l'exécution de helloworld devraient maintenant générer le résultat suivant:

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

L'aide à la configuration devrait également être mise à jour pour indiquer la valeur par défaut de my_option:

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

D'autres objets de configuration inclus dans la configuration helloworld, tels que FileLogger, acceptez également les options. L'option --log-level-display est intéressant, car il filtre les journaux qui apparaissent sur stdout. Plus tôt dans ce tutoriel, vous avez peut-être remarqué le message Monde ! J'ai un appareil..." le message de journal a cessé de s'afficher sur stdout est passé à FileLogger. Vous pouvez augmenter la verbosité vous connecter à stdout en transmettant l'argument --log-level-display ;

Essayez dès maintenant. Le message "I have device" (J'ai un appareil) devrait s'afficher. le message de journal réapparaît le stdout, en plus d'être connecté à un fichier:

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

C'est tout !

Pour rappel, si vous êtes bloqué(e) sur quelque chose, Commerce Le code source de la fédération contient de nombreuses informations utiles, qui ne sont pas exposées dans la documentation. Si le problème persiste, posez la question sur plate-forme-android le groupe Google, avec "Trade Fédération" dans l'objet du message.