Ce didacticiel vous guide dans la création d'une configuration de test "hello world" Trade Federation (TF) et vous donne une introduction pratique au framework TF. À partir d'un environnement de développement, vous créerez une configuration simple et ajouterez des fonctionnalités.
Le didacticiel 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 du test sont fournis, et le titre de chaque exercice est annoté d'une lettre décrivant les rôles impliqués dans cette étape :
- D pour Développeur
- I pour Intégrateur
- R pour testeur
Après avoir terminé le didacticiel, vous disposerez d'une configuration TF fonctionnelle et comprendrez de nombreux concepts importants du framework TF.
Création d'une fédération professionnelle
Pour plus de détails sur la configuration de l'environnement de développement TF, voir Configuration de la machine . Le reste de ce didacticiel suppose que vous avez ouvert un shell qui a été initialisé dans l'environnement TF.
Pour plus de simplicité, ce didacticiel illustre l'ajout d'une configuration et de ses classes à la bibliothèque principale du framework TF. Cela peut être étendu au développement de modules en dehors de l'arborescence des sources en compilant le JAR tradefed, puis en compilant vos modules avec ce JAR.
Création d'une classe de test (D)
Créons un test hello world qui envoie simplement un message à stdout. Un test tradefed implémente généralement l'interface IRemoteTest . Voici une implémentation pour le 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 depuis votre shell :
m -jN
Notez que CLog.i
dans l'exemple ci-dessus est utilisé pour diriger la sortie vers la console. Plus d'informations sur la connexion à Trade Federation sont décrites dans Logging (D, I, R) .
Si la construction ne réussit pas, consultez Machine Setup pour vous assurer que vous n'avez pas manqué une étape.
Créer une configuration (I)
Les tests Trade Federation sont rendus exécutables en créant une Configuration , un fichier XML qui indique à tradefed quel test (ou tests) exécuter, ainsi que les autres modules à exécuter et dans quel ordre.
Créons une nouvelle configuration pour notre HelloWorldTest (notez le nom complet de la classe de 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ù sur votre système de fichiers local (par exemple /tmp/helloworld.xml
). TF analysera le fichier XML de configuration (alias config ), chargera la classe spécifiée à l'aide de la réflexion, l'instanciera, la convertira en un IRemoteTest
et appellera sa méthode d' run
.
Exécution de la configuration (R)
Depuis votre shell, lancez la console tradefed :
tradefed.sh
Assurez-vous qu'un appareil est connecté à la machine hôte et qu'il est 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 run <config>
console. Essayer:
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!
Vous devriez voir "Hello, TF World!" sortie sur le terminal.
Vous pouvez confirmer qu'une commande est en cours d'exécution en utilisant list invocations
ou li
dans l'invite de la console, et elle ne devrait rien imprimer. 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}'
Ajout de la configuration au classpath (D, I, R)
Pour faciliter le déploiement, vous pouvez également regrouper les configurations dans les JAR tradefed eux-mêmes. Tradefed reconnaît automatiquement toutes les configurations placées dans les dossiers de configuration sur le classpath.
Pour illustrer, déplacez le fichier helloworld.xml
dans la bibliothèque principale de tradefed ( <tree>/tools/tradefederation/core/res/config/example/helloworld.xml
). Reconstruisez tradefed, redémarrez la console tradefed, puis demandez à tradefed d'afficher la liste des configurations du classpath :
tf> list configs […] example/helloworld: Runs the hello world test
Vous pouvez maintenant exécuter la configuration helloworld en utilisant :
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 d'exécuter des tests à l'aide d'appareils Android, alors ajoutons un appareil Android au test.
Les tests peuvent obtenir une référence à un appareil Android en utilisant TestInformation
, fourni par le framework lorsque la méthode IRemoteTest#run
est appelée.
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()); }
Reconstruisez 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
Prenez note du numéro de série indiqué comme Disponible ; c'est l'appareil qui doit être attribué à 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
Vous devriez voir le nouveau message d'impression affichant le numéro de série de l'appareil.
Envoi des résultats des tests (D)
IRemoteTest
rapporte les résultats en appelant des méthodes sur l'instance ITestInvocationListener fournie à la méthode #run
. Le framework TF lui-même est chargé de signaler le début (via ITestInvocationListener#invocationStarted ) et la fin (via ITestInvocationListener#invocationEnded ) de chaque Invocation.
Une exécution de test est une collection logique de tests. Pour signaler 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 et la fin de l'exécution de test.
Voici à quoi pourrait ressembler l'implémentation de HelloWorldTest avec un seul résultat de test échoué.
@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 la vôtre à 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 transmettre ces résultats à ITestInvocationListener
). Pour plus de détails, voir Types de tests .
Stockage des résultats de test (I)
L'implémentation de l'écouteur de test par défaut pour une configuration TF est TextResultReporter , qui vide les résultats d'un appel vers 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'un appel ailleurs, comme 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 similaire à celui utilisé par le rédacteur XML ant JUnit. Pour spécifier le result_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>
Reconstruisez maintenant tradefed et relancez 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 ressembler à ceci :
<?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'invocation personnalisés. Ils doivent simplement implémenter l'interface ITestInvocationListener .
Tradefed prend en charge plusieurs écouteurs d'invocation, vous pouvez donc envoyer les résultats des tests à plusieurs destinations indépendantes. Pour ce faire, spécifiez simplement plusieurs balises <result_reporter>
dans votre configuration.
Journalisation (D, I, R)
Les installations d'exploitation forestière de TF incluent la capacité de :
- Capturer les journaux de l'appareil (également appelé logcat de l'appareil)
- Enregistrez les journaux du cadre de la fédération commerciale en cours d'exécution sur la machine hôte (également appelé journal de l'hôte)
L'infrastructure TF capture automatiquement le logcat du périphérique alloué et l'envoie à l'écouteur d'invocation pour traitement. XmlResultReporter
enregistre ensuite le logcat du périphérique capturé sous forme de fichier.
Les journaux de l'hôte TF sont signalés à l'aide de l' encapsuleur CLog pour la classe ddmlib Log. Convertissons l'appel System.out.println
précédent dans HelloWorldTest en un 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, similaire à String.format
. Lorsque vous reconstruisez et réexécutez TF, vous devriez voir le 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, tradefed envoie les messages du journal de l'hôte à stdout . TF inclut également une implémentation de journal qui écrit des messages dans un fichier : FileLogger . Pour ajouter la journalisation des 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>
Maintenant, reconstruisez 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, lorsqu'il est affiché, doit contenir votre message de journal HelloWorldTest :
more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt
Exemple de sortie :
… 05-16 21:38:21 I/HelloWorldTest: Hello, TF World! I have device 004ad9880810a548
Options de manipulation (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 via l'utilisation de l'annotation @Option
.
Pour participer, une classe d'objets Configuration applique l'annotation @Option
à un champ membre et lui attribue un nom unique. Cela permet à cette valeur de champ de membre d'être renseignée via une option de ligne de commande (et ajoute également automatiquement cette option au système d'aide à la configuration).
Remarque : Tous les types de champs ne sont pas pris en charge. Pour une description des types pris en charge, voir OptionSetter .
Ajoutons une @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 que nous puissions démontrer qu'elle a été correctement reçue :
@Override public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { … CLog.logAndDisplay(LogLevel.INFO, "I received option '%s'", mMyOption);
Enfin, reconstruisez TF et exécutez helloworld ; vous devriez voir un message de journal avec la valeur par défaut de my_option
:
tf> run example/helloworld … 05-24 18:30:05 I/HelloWorldTest: I received option 'thisisthedefault'
Passer des valeurs depuis la ligne de commande
Passez une valeur pour my_option
; vous devriez voir my_option
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-le maintenant et 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 concernant "imprimer uniquement les options importantes". Pour réduire l'encombrement de l'aide sur les options, TF utilise l'attribut Option#importance
pour déterminer s'il faut afficher un texte d'aide de champ @Option
particulier lorsque --help
est spécifié. --help-all
affiche toujours l'aide pour tous les champs @Option
, quelle que soit leur importance. Pour plus de détails, voir Option.Importance .
Passer des valeurs 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 produire cette sortie :
05-24 20:38:25 I/HelloWorldTest: I received option 'fromxml'
L'aide à la configuration devrait également se mettre à 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 les options. L'option --log-level-display
est intéressante car elle filtre les logs qui s'affichent sur stdout. Plus tôt dans le didacticiel, vous avez peut-être remarqué que le message de journal "Hello, TF World! J'ai un appareil …" a cessé de s'afficher sur stdout après que nous sommes passés à l'utilisation de FileLogger
. Vous pouvez augmenter la verbosité de la journalisation sur stdout en passant le --log-level-display
arg.
Essayez ceci maintenant, et vous devriez voir le message de journal "J'ai un appareil" réapparaître sur 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, les amis !
Pour rappel, si vous êtes bloqué sur quelque chose, le code source de la Trade Federation contient de nombreuses informations utiles qui ne sont pas exposées dans la documentation. Si tout le reste échoue, essayez de demander sur le groupe Google de la plate-forme Android, avec "Trade Federation" dans l'objet du message.