Ejemplo de prueba de TF de extremo a extremo

En este instructivo, aprenderás a crear “Hello World” Federación de Comercio (Tradefed o TF) y ofrece una introducción práctica a la TF en un framework de aplicaciones. A partir de un entorno de desarrollo, configuración y agregar funciones.

El tutorial presenta el proceso de desarrollo de prueba como un conjunto de ejercicios, cada uno de varios pasos que demuestran cómo compilar definir mejor tu configuración. Todo el código de muestra que necesitas para completar la prueba se proporciona la configuración y el título de cada ejercicio se anota con una carta que describa las funciones involucradas en ese paso:

  • D para el desarrollador
  • I para Integrator
  • R para el ejecutor de pruebas

Después de completar el instructivo, tendrás una configuración de TF en funcionamiento y comprenda muchos conceptos importantes del framework de TF.

Configurar la Federación de Comercio

Para obtener detalles sobre la configuración del entorno de desarrollo de TF, consulta Máquina Configuración. En el resto de este instructivo, se da por sentado que tienes una shell abierta inicializado en el entorno de TF.

Para simplificar, en este instructivo se ilustra cómo agregar una configuración y sus a la biblioteca principal del framework de TF. Esto se puede extender al desarrollo fuera del árbol de fuentes con la compilación del JAR de intercambio y, luego, los módulos con ese JAR.

Crear una clase de prueba (D)

Creemos una prueba de Hello World que solo vuelque un mensaje en stdout. R la prueba de Tradefed generalmente implementa IRemoteTest; interfaz de usuario. Esta es una implementación para 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!");
    }
}

Guarda este código de muestra en <tree>/tools/tradefederation/core/src/com/android/tradefed/example/HelloWorldTest.java y recompilar el intercambio desde la shell:

m -jN

Ten en cuenta que CLog.i en el ejemplo anterior se usa para dirigir la salida a la consola. Más En Registro (D, I, R), se describe la información sobre la creación de registros en la Federación de Comercio.

Si la compilación no se realiza correctamente, consulta Máquina Configuración para asegurarte de no perderte ningún paso.

Crear una configuración (I)

Las pruebas de la Federación de Comercio se pueden ejecutar creando un Configuration, un archivo en formato XML que indica en qué comercio prueba (o pruebas) para ejecutar, así como qué otros módulos ejecutar y en qué en el orden personalizado.

Creemos una nueva configuración para HelloWorldTest (ten en cuenta que la clase completa nombre de HelloWorldTest):

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

Guarda estos datos en un archivo helloworld.xml en cualquier parte de tu entorno local. un sistema de archivos (por ejemplo, /tmp/helloworld.xml). TF analizará los Archivo de configuración en formato XML (también conocido como config), carga la clase especificada usando reflejo, crea una instancia, transmítela a un objeto IRemoteTest y llama a su run.

Ejecuta la configuración (R)

Desde tu shell, inicia la consola de intercambio:

tradefed.sh

Asegúrate de que un dispositivo esté conectado a la máquina anfitrión y sea visible para el intercambio:

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

Las configuraciones se pueden ejecutar con run <config>. Comando de la consola. Prueba lo siguiente:

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!

Deberías ver “Hello, TF World!” de salida en la terminal.

Puedes confirmar que se termine de ejecutar un comando con list invocations. l i en el mensaje de la consola, y no debería imprimir nada. Si los comandos están actualmente en ejecución, se muestran de la siguiente manera:

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

Agrega la configuración a la ruta de clase (D, I, R)

Para mayor comodidad de la implementación, también puedes agrupar los parámetros de configuración en la distribución JAR en sí. Tradefed reconoce automáticamente todas las configuraciones config en la ruta de clase.

A modo de ejemplo, mueve el archivo helloworld.xml al objeto Tradefed biblioteca principal (<tree>/tools/tradefederation/core/res/config/example/helloworld.xml) Vuelve a compilar el intercambio, reinicia la consola del intercambio y pídele al intercambio que muestre el de configuración de la ruta de clase:

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

Ahora puedes ejecutar la configuración de helloworld con el siguiente comando:

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!

Interactuar con un dispositivo (D, R)

Hasta ahora, HelloWorldTest no está haciendo nada interesante. Tradefed especializada es ejecutar pruebas con dispositivos Android, así que agreguemos un dispositivo Android. a prueba.

Las pruebas pueden obtener una referencia a un dispositivo Android usando TestInformation, proporcionado por el framework cuando se llama al método IRemoteTest#run.

Modifiquemos el mensaje de impresión HelloWorldTest para mostrar el número de serie de el dispositivo:

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

Ahora, vuelve a compilar el canal de Exchange y revisa la lista de dispositivos:

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

Anota el número de serie que aparece como Available. es decir, el dispositivo que debería asignarse 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

Deberías ver el nuevo mensaje de impresión con el número de serie del dispositivo.

Enviar los resultados de la prueba (D)

IRemoteTest informa los resultados llamando a los métodos en el ITestInvocationListener. proporcionada al método #run. El framework de TF en sí es responsable de informar el inicio (mediante ITestInvocationListener#invocationStarted) y finalizan (mediante ITestInvocationListener#invocationEnded) de cada Invocación.

Una ejecución de pruebas es una colección lógica de pruebas. Para informar los resultados de las pruebas, sigue estos pasos: IRemoteTest es responsable de informar el inicio de una ejecución de prueba. el inicio y el final de cada prueba y el final de su ejecución.

Así es como se vería la implementación de HelloWorldTest con un solo resultado fallido de la prueba.

@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 incluye varias implementaciones de IRemoteTest que puedes reutilizar en lugar de escribir la tuya desde cero. Por ejemplo: Prueba de instrumentación puede ejecutar las pruebas de una aplicación para Android de forma remota en un dispositivo Android, analizar la y reenviar esos resultados a ITestInvocationListener). Para obtener más información, consulta Probar Tipos.

Almacenar los resultados de la prueba (I)

La implementación predeterminada del objeto de escucha de prueba para una configuración de TF es TextResultReporter que que vuelca los resultados de una invocación en stdout. A modo de ejemplo, ejecuta el Configuración de HelloWorldTest de la sección anterior:

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

Para almacenar los resultados de una invocación en otro lugar, como en un archivo, especifica un implementación personalizada de ITestInvocationListener con el result_reporter en tu configuración.

TF también incluye la XmlResultReporter. de objetos de escucha, que escribe los resultados de la prueba en un archivo XML en un formato similar al que usa el escritor XML ant JUnit. Para especificar result_reporter en la de Terraform, edita el …/res/config/example/helloworld.xml configuración:

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

Ahora, vuelve a compilar el protocolo Tradefed y ejecuta nuevamente la muestra de 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

Observa el mensaje de registro que indica que se generó un archivo en formato XML. el el archivo generado debería verse así:

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

También puedes escribir tus propios objetos de escucha de invocación personalizados; solo tienen que necesitas implementar el ITestInvocationListener. interfaz de usuario.

Tradefed admite varios objetos de escucha de invocación, por lo que puedes enviar resultados de prueba a múltiples destinos independientes. Para ello, simplemente especifica varias Etiquetas <result_reporter> en tu configuración.

Instalaciones de registro (D, I, R)

Las utilidades de registro de TF incluyen la capacidad de realizar las siguientes acciones:

  1. Captura registros del dispositivo (también conocido como logcat de dispositivo)
  2. Registrar registros del marco de la Federación de Comercio que se ejecutan en la máquina anfitrión (también conocido como registro del host)

El framework de TF captura automáticamente el logcat del dispositivo asignado. y lo envía al objeto de escucha de invocación para su procesamiento. Luego, XmlResultReporter guarda el logcat del dispositivo capturado como un archivo.

Los registros del host de TF se informan Wrapper de CLog para la clase de registro ddmlib. Vamos a convertir llamada System.out.println anterior en HelloWorldTest a un Llamada de CLog:

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

CLog controla la interpolación de cadenas directamente, de manera similar a String.format Cuando vuelvas a compilar y a ejecutar TF, deberías ver el mensaje de registro en stdout:

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

De forma predeterminada, resultados del registro del host mensajes a stdout. TF también incluye una implementación de registros que escribe mensajes a un archivo: FileLogger Para agregar un registro de archivos, agrega una etiqueta logger a la configuración y especifica la nombre completo de la clase 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>

Ahora, vuelve a compilar y ejecuta el ejemplo de 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
…

El mensaje de registro indica la ruta del registro del host, que, cuando se visualiza, debe contener el mensaje de registro de HelloWorldTest:

more /tmp/0/inv_6390011618174565918/host_log_4255420317120216614.txt

Resultado de ejemplo:

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

Opciones de manejo (D, I, R)

Objetos cargados desde una configuración de TF (también conocida como objetos de configuración) también puede recibir datos de argumentos de la línea de comandos @Option.

Para participar, una clase de objeto Configuration aplica el @Option una anotación a un campo de miembro y le otorga un nombre único. Esto permite que el valor del campo de miembro que se propagará con una opción de línea de comandos (y también agrega automáticamente esa opción al sistema de ayuda de configuración).

Nota: No todos los tipos de campos son compatibles. Para un descripción de los tipos admitidos, consulta OptionSetter.

Agreguemos un @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";

A continuación, agregaremos un mensaje de registro para mostrar el valor de la opción en HelloWorldTest para que podamos demostrar que se recibió correctamente:

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

Por último, vuelve a compilar TF y ejecuta helloworld. deberías ver un mensaje de registro Valor predeterminado de my_option:

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

Pasa valores desde la línea de comandos

Pasa un valor para my_option. deberías ver my_option propagado con ese valor:

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

Los parámetros de configuración de TF también incluyen un sistema de ayuda, que muestra automáticamente texto de ayuda para @Option campos. Pruébalo ahora. Deberías ver el Texto de ayuda para 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.

Observa el mensaje "imprimir solo las opciones importantes". Para reducir opción ayuda a desordenar, TF usa el atributo Option#importance para determinar si se muestra un texto de ayuda del campo @Option en particular cuando Se especifica --help. --help-all siempre muestra ayuda para todos los campos @Option, independientemente de la importancia. Para obtener más información, consulta Opción.Importancia.

Cómo pasar valores de una configuración

También puedes especificar un valor de opción en la configuración agregando un <option name="" value="">. Pruébalo con helloworld.xml:

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

Si vuelves a compilar y ejecutar helloworld, ahora se debería producir el siguiente resultado:

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

La ayuda de configuración también debe actualizarse para indicar el valor predeterminado de my_option:

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

Otros objetos de configuración incluidos en la configuración de helloworld, como FileLogger, también acepta opciones. La opción --log-level-display es interesante porque filtra los registros que aparecer en stdout. Anteriormente en el instructivo, quizás hayas notado el mensaje “Hello, TF ¡Mundial! Tengo dispositivo... el mensaje de registro dejó de mostrarse en stdout después de que pasó a usar FileLogger. Puedes aumentar la verbosidad de registro en stdout pasando el argumento --log-level-display

Pruébalo ahora. Deberías ver el mensaje “Tengo dispositivo” los mensajes de registro volverán a aparecer en stdout, además de registrarse en un archivo:

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

¡Eso es todo, amigos!

Como recordatorio, si estás atascado en algo, el Comercio El código fuente de federación tiene mucha información útil que no se expone en la documentación. Si todo lo demás falla, intenta preguntar en el plataforma-android Grupo de Google con la "Federación de Comercio" en el asunto del mensaje.