Ejemplo de pruebas de instrumentación autónoma

Cuando se inicia una prueba de instrumentación, con código de instrumentación insertado y, luego, iniciado para la ejecución. Uno es que el paquete de destino no puede ser la aplicación para Android en su propio framework, como el paquete android, porque paradójica en la que tendría que reiniciarse el framework de Android, lo que es lo que admite las funciones del sistema, incluida la propia instrumentación.

Esto significa que una prueba de instrumentación no puede insertarse en Android. de seguridad, también conocido como el servidor del sistema, para la ejecución. Para probar el SDK de prueba, el código de prueba solo puede invocar plataformas de APIs públicas o aquellas expuestas con el lenguaje de definición de la interfaz de Android AIDL disponibles en el árbol de fuentes de la plataforma. Para esta categoría de pruebas, no es importante orientarse a ningún paquete en particular. Por lo tanto, es habitual que y las instrumentaciones que se deben declarar para tener como objetivo su propio paquete de aplicación de prueba, como definido en su propia etiqueta <manifest> de AndroidManifest.xml.

Según los requisitos, es posible que los paquetes de aplicación de prueba en esta categoría también:

  • Agrupa las actividades necesarias para realizar pruebas.
  • Comparte el ID de usuario con el sistema.
  • Debe estar firmado con la clave de plataforma.
  • Compilar con la fuente del framework, en lugar del SDK público

A veces, esta categoría de pruebas de instrumentación se conoce como la instrumentación autónoma. Estos son algunos ejemplos de pruebas de instrumentación autónoma la fuente de la plataforma:

En el ejemplo que se aborda aquí, se escribe una nueva prueba de instrumentación con objetivos configurado en su propio paquete de aplicación de prueba. En esta guía, se utilizan los siguientes a modo de ejemplo:

Se recomienda explorar el código primero para obtener una impresión aproximada antes de continuar.

Elige una ubicación de origen

Normalmente, tu equipo ya tendrá un patrón establecido de lugares para comprobar en código y lugares donde agregar pruebas. La mayoría de los equipos tienen un solo repositorio de Git. comparten uno con otros equipos, pero tienen un subdirectorio dedicado que contiene el código fuente del componente.

Si suponemos que la ubicación raíz de tu fuente de componentes es <component source root>, la mayoría de los componentes tienen carpetas src y tests en ella, y algunos componentes archivos adicionales, como Android.mk (o divididos en archivos .mk adicionales), el archivo de manifiesto AndroidManifest.xml y el archivo de configuración de prueba "AndroidTest.xml".

Dado que agregarás una prueba nueva, probablemente debas crear tests junto al componente src y propágalo con contenido.

En algunos casos, tu equipo puede tener estructuras de directorios adicionales en tests. debido a la necesidad de empaquetar diferentes paquetes de pruebas en APK individuales. Y En este caso, deberás crear un nuevo subdirectorio en tests.

Independientemente de la estructura, terminarás propagando el directorio tests o el subdirectorio recién creado con archivos similares al que contiene Directorio instrumentation en el cambio de Gerrit de muestra. Los detalles de cada se explican más adelante en este documento.

Archivo de manifiesto

Al igual que con un proyecto de app, cada módulo de prueba de instrumentación requiere un de manifiesto llamado AndroidManifest.xml. Para incluir automáticamente este archivo con el makefile principal BUILD_PACKAGE, proporciona este archivo junto al Android.mk para tu módulo de prueba.

Si no estás familiarizado con el archivo AndroidManifest.xml, consulta la Descripción general del manifiesto de la app

A continuación, se incluye un archivo AndroidManifest.xml de muestra:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  android:sharedUserId="android.uid.system"
  package="android.test.example.helloworld" >

    <application>
       <uses-library android:name="android.test.runner"/>
    </application>

    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                     android:targetPackage="android.test.example.helloworld"
                     android:label="Hello World Test"/>

</manifest>

Algunas observaciones seleccionadas sobre el archivo de manifiesto:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.test.example.helloworld" >

El atributo package es el nombre del paquete de la aplicación: es el único identificador que usa el framework de la aplicación para Android para identificar una tu aplicación de prueba (o, en este contexto, tu aplicación de prueba). Cada usuario del sistema solo puede instalar una aplicación con ese nombre de paquete.

Además, este atributo package es igual a lo que ComponentName#getPackageName() y las que también usarías para interactuar con varias suscripciones de pm usa adb shell.

Si bien el nombre del paquete suele tener el mismo estilo, como nombre de paquete de Java, tiene muy pocas cosas que ver con él. En otro palabras, tu paquete de aplicación (o prueba) puede contener clases con cualquier paquete nombres, aunque por otro lado, podrías optar por la simplicidad y hacer que tus nombre de paquete de Java en tu aplicación o prueba idéntica a la de la aplicación el nombre del paquete.

android:sharedUserId="android.uid.system"

Esto declara que, en el momento de la instalación, a este archivo APK se le debe otorgar el con el mismo ID de usuario (identidad del entorno de ejecución) que la plataforma principal. Ten en cuenta que es depende de que el APK se firme con el mismo certificado que el de la plataforma principal. (consulta LOCAL_CERTIFICATE en la sección anterior), pero son diferentes conceptos:

  • algunos permisos o APIs están protegidos por firmas, lo que requiere lo mismo certificado de firma
  • algunos permisos o APIs requieren la identidad de usuario system del emisor. que requiere que el paquete que realiza la llamada comparta el ID del usuario con system, si se trata de un paquete separado de la plataforma principal
<uses-library android:name="android.test.runner" />

Esto es obligatorio para todas las pruebas de instrumentación, ya que las clases relacionadas son empaquetado en un archivo de biblioteca JAR del framework independiente, por lo que se requiere classpath cuando el framework de la aplicación invoca el paquete de prueba.

android:targetPackage="android.test.example.helloworld"

Quizás notaste que targetPackage se declara igual que el Se declaró el atributo package en la etiqueta manifest de este archivo. Como se menciona en conceptos básicos de pruebas, esta categoría de pruebas de instrumentación se normalmente está destinado a probar las APIs del framework, por lo que no es muy útil para que tengan un paquete de aplicación objetivo específico, además de sí mismo.

Archivo de configuración simple

Cada módulo de prueba nuevo debe tener un archivo de configuración para dirigir el sistema de compilación con metadatos de módulos, dependencias de tiempo de compilación y empaquetado instrucciones. En la mayoría de los casos, la opción de archivo de Blueprint basado en Soong es suficientes. Para obtener más información, consulta Configuración de prueba simple.

Archivo de configuración complejo

Para estos casos más complejos, también debes escribir una configuración de prueba. para el agente de prueba de Android, Federación de Comercio.

La configuración de prueba puede especificar opciones especiales de configuración de dispositivos para proporcionar la clase de prueba. Consulta el ejemplo en /platform_testing/tests/example/instrumentation/AndroidTest.xml.

Aquí se incluye un resumen para tu comodidad:

<configuration description="Runs sample instrumentation test.">
  <target_preparer class="com.android.tradefed.targetprep.TestFilePushSetup"/>
  <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
    <option name="test-file-name" value="HelloWorldTests.apk"/>
  </target_preparer>
  <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"/>
  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"/>
  <option name="test-suite-tag" value="apct"/>
  <option name="test-tag" value="SampleInstrumentationTest"/>

  <test class="com.android.tradefed.testtype.AndroidJUnitTest">
    <option name="package" value="android.test.example.helloworld"/>
    <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
  </test>
</configuration>

Algunas observaciones seleccionadas sobre el archivo de configuración de prueba:

<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
  <option name="test-file-name" value="HelloWorldTests.apk"/>
</target_preparer>

Esto le indica a la Federación de Comercio que instale HelloWorldTests.apk en el objetivo. usando un target_preparer especificado. Hay muchos preparadores de objetivos disponibles para los programadores de la Federación de Comercio y se pueden utilizar para garantizar que el dispositivo esté configurado correctamente antes de la ejecución de la prueba.

<test class="com.android.tradefed.testtype.AndroidJUnitTest">
  <option name="package" value="android.test.example.helloworld"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Especifica la clase de prueba de la Federación de Comercio que se usará para ejecutar la prueba y pase el paquete en el dispositivo que se ejecutará y el ejecutor de pruebas que, en este caso, es JUnit.

Para obtener más información, consulta Prueba la configuración del módulo.

Funciones de JUnit4

El uso de la biblioteca android-support-test como ejecutor de pruebas permite la adopción de nuevos JUnit4, y el cambio de gerrit de muestra contiene algunas uso de sus funciones. Consulta el ejemplo en /platform_testing/tests/example/instrumentation/src/android/test/example/helloworld/HelloWorldTest.java.

Si bien los patrones de prueba suelen ser específicos de los equipos de componentes, hay algunos patrones de uso generalmente útiles.

@RunWith(JUnit4.class)
public class HelloWorldTest {

Una diferencia significativa en JUnit4 es que las pruebas ya no son necesarias para heredarán de una clase de prueba base común; en su lugar, escribes pruebas en Java simple y usa anotaciones para indicar ciertas restricciones y configuraciones de prueba. En en este ejemplo, se indica que esta clase se debe ejecutar como una prueba de JUnit4.

    @BeforeClass
    public static void beforeClass() {
    ...
    @AfterClass
    public static void afterClass() {
    ...
    @Before
    public void before() {
    ...
    @After
    public void after() {
    ...
    @Test
    @SmallTest
    public void testHelloWorld() {
    ...

JUnit4 usa las anotaciones @Before y @After en los métodos para realizar la configuración previa a la prueba y el desmontaje posterior a la prueba. De manera similar, @BeforeClass y Se usan anotaciones @AfterClass en los métodos de JUnit4 para realizar la configuración antes Ejecutar todas las pruebas en una clase de prueba y, luego, realizar la eliminación. Ten en cuenta que Los métodos de desmontaje y configuración del alcance de clase deben ser estáticos. En cuanto a los métodos de prueba, a diferencia de la versión anterior de JUnit, ya no es necesario iniciar el nombre del método con test, en cambio, cada una de ellas debe anotarse con @Test. Como siempre, Los métodos de prueba deben ser públicos, no deben declarar ningún valor que se muestre, no tomar parámetros y puede generar excepciones.

Acceso a las clases de instrumentación

Aunque no se trata en el ejemplo básico de Hello World, es bastante común que Prueba de Android para solicitar acceso a la instancia Instrumentation: esta es la API principal que brinda acceso a contextos de aplicaciones, ciclo de vida de la actividad APIs de prueba relacionadas y más.

Debido a que las pruebas JUnit4 ya no requieren una clase base común, ya no es necesario para obtener la instancia Instrumentation mediante En cambio, InstrumentationTestCase#getInstrumentation() es el nuevo ejecutor de pruebas. lo administra a través de InstrumentationRegistry en la que la configuración contextual y del entorno creada por un framework de instrumentación se almacenan.

Para acceder a la instancia de la clase Instrumentation, simplemente llama al método estático getInstrumentation() en la clase InstrumentationRegistry:

Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation()

Compila y prueba de forma local

Para los casos de uso más comunes, emplea Atest (Atest).

Para casos más complejos que requieren una mayor personalización, sigue las instrucciones de instrumentación.