Ce tutoriel vous explique comment créer une configuration de test "Hello World" pour la Trade Federation (Tradefed ou TF) et vous présente le framework TF de manière pratique. À partir d'un environnement de développement, vous allez créer une configuration simple et ajouter des fonctionnalités.
Le tutoriel présente le processus de développement de test sous la forme d'un ensemble d'exercices, chacun composé de plusieurs étapes, qui montrent comment créer et affiner progressivement votre configuration. Tous les exemples de code dont vous avez besoin pour terminer la configuration des tests sont fournis, et le titre de chaque exercice est annoté d'une lettre décrivant les rôles impliqués à cette étape:
- D pour "Developer" (Développeur)
- I pour "Integrator" (Intégrateur)
- R pour Test Runner
Une fois le tutoriel terminé, vous disposerez d'une configuration TF fonctionnelle et vous comprendrez de nombreux concepts importants du framework TF.
Configurer la fédération du commerce
Pour en savoir plus sur la configuration de l'environnement de développement TF, consultez la section Configuration de la machine. La suite de ce tutoriel part du principe que vous avez ouvert un shell qui a été initialisé dans l'environnement TF.
Par souci de simplicité, ce tutoriel illustre l'ajout d'une configuration et de ses classes à la bibliothèque principale du framework TF. Vous pouvez étendre cette approche au développement de modules en dehors de l'arborescence source en compilant le fichier JAR de tradefed, puis en compilant vos modules avec ce fichier JAR.
Créer une classe de test (D)
Créons un test "Hello World" qui ne fait que transmettre un message à la sortie standard. Un test de distribution intégrée implémente généralement l'interface IRemoteTest. Voici une implémentation de 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
et reconstruisez tradefed à partir de votre shell:
m -jN
Notez que CLog.i
dans l'exemple ci-dessus est utilisé pour rediriger la sortie vers la console. Pour en savoir plus sur la journalisation dans Trade Federation, consultez Journalisation (D, I, R).
Si la compilation échoue, consultez la section Configuration de la machine pour vous assurer que vous n'avez pas manqué d'étape.
Créer une configuration (I)
Les tests de la Trade Federation sont exécutables en créant une configuration, un fichier XML qui indique à Tradefed le ou les tests à exécuter, ainsi que les autres modules à exécuter et dans quel ordre.
Créons une configuration pour notre HelloWorldTest (notez le nom complet 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
n'importe où dans votre système de fichiers local (par exemple, /tmp/helloworld.xml
). TF analysera le fichier XML de configuration (également appelé config), chargera la classe spécifiée à l'aide de la réflexion, l'instanciera, la castera en IRemoteTest
et appellera sa méthode run
.
Exécuter la configuration (R)
Depuis votre shell, lancez la console tradefed:
tradefed.sh
Assurez-vous qu'un appareil est connecté à la machine hôte et visible par tradefed:
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 la commande de console run <config>
. 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!" (Bonjour, monde TF !) doit s'afficher dans le terminal.
Vous pouvez vérifier qu'une commande est terminée à l'aide de list invocations
ou l i
dans l'invite de la console. Aucun résultat ne devrait s'afficher. Si des commandes sont 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 d'accès aux classes (D, I, R)
Pour faciliter le déploiement, vous pouvez également regrouper les configurations dans les fichiers JAR de tradefed. Tradefed reconnaît automatiquement toutes les configurations placées dans les dossiers config du chemin d'accès aux classes.
Pour illustrer, déplacez le fichier helloworld.xml
dans la bibliothèque principale de tradefed (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml
). Recompilez tradefed, redémarrez la console tradefed, puis demandez à tradefed d'afficher la liste des configurations à partir du chemin d'accès aux classes:
tf> list configs […] example/helloworld: Runs the hello world test
Vous pouvez maintenant exécuter la configuration helloworld à l'aide de:
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)
Jusqu'à présent, notre HelloWorldTest ne fait rien d'intéressant. La spécialité de Tradefed est l'exécution de tests à l'aide d'appareils Android. Ajoutons donc un appareil Android au test.
Les tests peuvent obtenir une référence à un appareil Android à l'aide de TestInformation
, fourni par le framework lors de l'appel de la méthode IRemoteTest#run
.
Modifions le message d'impression HelloWorldTest pour afficher le numéro de série de l'appareil:
@Override public void run(TestInformation testInfo, ITestInvocationListener listener) throws DeviceNotAvailableException { CLog.i("Hello, TF World! I have device " + testInfo.getDevice().getSerialNumber()); }
Recréez maintenant tradefed 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 Available (Disponible). Il s'agit de 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 affichant le numéro de série de l'appareil devrait s'afficher.
Envoyer les résultats des tests (D)
IRemoteTest
signale les résultats en appelant des méthodes sur l'instance ITestInvocationListener fournie à la méthode #run
. Le framework TF lui-même est responsable de signaler le début (via ITestInvocationListener#invocationStarted) et la fin (via ITestInvocationListener#invocationEnded) de chaque invocation.
Une exécution de test est un ensemble logique de tests. Pour générer des rapports sur les résultats des tests, IRemoteTest
est chargé de signaler le début d'une exécution de test, le début et la fin de chaque test, ainsi que la fin de l'exécution de test.
Voici à quoi pourrait ressembler l'implémentation de HelloWorldTest avec un seul résultat de test non réussi.
@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, InstrumentationTest peut exécuter les tests d'une application Android à distance sur un appareil Android, analyser les résultats et les transmettre à ITestInvocationListener
. Pour en savoir plus, consultez la section Types de test.
Résultats du test en magasin (I)
L'implémentation par défaut de l'écouteur de test pour une configuration TF est TextResultReporter, qui vide les résultats d'une invocation dans stdout. Pour illustrer, exécutez la 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 une implémentation ITestInvocationListener
personnalisée à l'aide de la balise result_reporter
dans votre configuration.
TF inclut également l'écouteur XmlResultReporter, qui écrit les résultats des tests dans un fichier XML dans un format semblable à celui utilisé par l'outil d'écriture XML JUnit ant. Pour spécifier le résultat_reporter dans la configuration, modifiez la configuration …/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>
Recompilez maintenant tradefed 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é. Le fichier généré devrait 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 doivent simplement implémenter l'interface ITestInvocationListener.
Tradefed accepte plusieurs écouteurs d'appel, ce qui vous permet d'envoyer les résultats des tests à plusieurs destinations indépendantes. Pour ce faire, il vous suffit de spécifier plusieurs balises <result_reporter>
dans votre configuration.
Installations de journalisation (D, I, R)
Les fonctionnalités de journalisation de TF permettent de:
- Enregistrer les journaux de l'appareil (logcat de l'appareil)
- Enregistrer les journaux du framework Trade Federation exécuté sur la machine hôte (journal de l'hôte)
Le framework TF capture automatiquement le logcat 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 CLog pour la classe de journal ddmlib. Convertissons l'appel System.out.println
précédent dans HelloWorldTest en 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 String.format
. Lorsque vous recompilez et réexécutez TF, le message de journal doit s'afficher sur stdout:
tf> run example/helloworld … 05-16 21:30:46 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548 …
Par défaut, tradefed affiche les messages de journal de l'hôte dans stdout. TF inclut également une implémentation de journalisation qui écrit des messages dans un fichier : FileLogger.
Pour ajouter la journalisation de fichiers, ajoutez une balise logger
à la configuration, en spécifiant le nom de classe complet de 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>
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 d'accès au journal de l'hôte, qui, lorsqu'il est consulté, 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)
Les objets chargés à partir d'une configuration TF (également appelés objets de configuration) peuvent également recevoir des données à partir d'arguments de ligne de commande à l'aide de l'annotation @Option
.
Pour participer, une classe d'objets de configuration applique l'annotation @Option
à un champ membre et lui attribue un nom unique. Cela permet de renseigner la valeur du champ de membre via une option de ligne de commande (et ajoute automatiquement cette option au système d'aide de la configuration).
Remarque:Tous les types de champs ne sont pas acceptés. Pour en savoir plus sur les types acceptés, consultez 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 démontrer qu'elle a été reçue correctement:
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { … CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);
Enfin, reconstruisez TF et exécutez helloworld. Un message de journal avec la valeur par défaut de my_option
devrait s'afficher:
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
. my_option
devrait être 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 le texte d'aide pour les champs @Option
. Essayez maintenant. Vous devriez voir le 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 indiquant que seules les options importantes sont imprimées. Pour réduire l'encombrement des options d'aide, TF utilise l'attribut Option#importance
pour déterminer si un texte d'aide de champ @Option
particulier doit être affiché lorsque --help
est spécifié. --help-all
affiche toujours une 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 d'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 recompilation et l'exécution de helloworld devraient maintenant générer la sortie suivante:
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
L'aide de 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
, acceptent également des options. L'option --log-level-display
est intéressante, car elle filtre les journaux qui s'affichent sur stdout. Plus tôt dans le tutoriel, vous avez peut-être remarqué le message "Hello, TF World! Le message de journal "device …" n'est plus affiché sur stdout après avoir commencé à utiliser FileLogger
. Vous pouvez augmenter le niveau de détail de la journalisation dans la sortie standard en transmettant l'argument --log-level-display
.
Essayez maintenant. Le message de journal "I have device" (J'ai un appareil) devrait réapparaître sur stdout, en plus d'être consigné dans 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 terminé !
Pour rappel, si vous rencontrez un problème, le code source de la Fédération du commerce contient de nombreuses informations utiles qui ne figurent pas dans la documentation. Si vous ne trouvez pas de réponse, essayez de poser votre question sur le groupe Google android-platform, en indiquant "Trade Federation" dans l'objet du message.