Ejemplo de segmentación para una app

Esta categoría de pruebas de instrumentación no es muy diferente de las que se dirigen a las aplicaciones de Android normales. Cabe destacar que la aplicación de prueba que incluía la instrumentación debe firmarse con el mismo certificado que la aplicación a la que se dirige.

Ten en cuenta que en esta guía se supone que ya tienes algunos conocimientos sobre el flujo de trabajo del árbol de fuentes de la plataforma. De lo contrario, consulta los requisitos. En el ejemplo que se aborda aquí, se escribe una nueva prueba de instrumentación con el paquete de destino establecido en su propio paquete de aplicación de prueba. Si no conoces el concepto, lee la Introducción a las pruebas de la plataforma.

En esta guía, se usa la siguiente prueba de seguimiento como ejemplo:

  • frameworks/base/packages/Shell/tests

Se recomienda que primero explores el código para tener una idea general antes de continuar.

Decide una ubicación de origen

Dado que la prueba de instrumentación se orientará a una aplicación, la convención es colocar el código fuente de la prueba en un directorio tests debajo de la raíz del directorio de origen del componente en el árbol de origen de la plataforma.

Consulta más debates sobre la ubicación de la fuente en el ejemplo de extremo a extremo para pruebas de auto-instrumentación.

Archivo de manifiesto

Al igual que una aplicación normal, cada módulo de prueba de instrumentación necesita un archivo de manifiesto. Si nombras el archivo como AndroidManifest.xml y lo proporcionas junto a Android.mk para tu módulo de prueba, se incluirá automáticamente en el archivo make principal BUILD_PACKAGE.

Antes de continuar, te recomendamos que primero revises la Descripción general del manifiesto de la app.

En esta sección, se proporciona una descripción general de los componentes básicos de un archivo de manifiesto y sus funcionalidades.

Se puede acceder a la versión más reciente del archivo de manifiesto para el cambio de Gerrit de muestra en: https://android.googlesource.com/platform/frameworks/base/+/android16-release/packages/Shell/tests/AndroidManifest.xml

Aquí se incluye una instantánea para mayor comodidad:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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

        <activity
            android:name="com.android.shell.ActionSendMultipleConsumerActivity"
            android:label="ActionSendMultipleConsumer"
            android:theme="@android:style/Theme.NoDisplay"
            android:noHistory="true"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.SEND_MULTIPLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="*/*" />
            </intent-filter>
        </activity>
    </application>

    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
        android:targetPackage="com.android.shell"
        android:label="Tests for Shell" />

</manifest>

Algunos comentarios sobre el archivo de manifiesto:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.shell.tests">

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

Dado que se trata de un paquete de aplicación de prueba, independiente del paquete de aplicación en proceso de prueba, se debe usar un nombre de paquete diferente: una convención común es agregar un sufijo .test.

Además, este atributo package es el mismo que devuelve ComponentName#getPackageName() y el mismo que usarías para interactuar con varios subcomandos de pm a través de adb shell.

Ten en cuenta también que, si bien el nombre del paquete suele tener el mismo estilo que un nombre de paquete de Java, en realidad tiene muy poco que ver con él. En otras palabras, el paquete de tu aplicación (o prueba) puede contener clases con cualquier nombre de paquete, aunque, por otro lado, puedes optar por la simplicidad y tener el nombre del paquete Java de nivel superior en tu aplicación o prueba idéntico al nombre del paquete de la aplicación.

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

Esto es necesario para todas las pruebas de Instrumentation, ya que las clases relacionadas se empaquetan en un archivo .jar de biblioteca de framework independiente, por lo que se requieren entradas de ruta de clase adicionales cuando el framework de la aplicación invoca el paquete de prueba.

android:targetPackage="com.android.shell"

Esto establece el paquete de destino de la instrumentación en com.android.shell. Cuando se invoca la instrumentación a través del comando am instrument, el framework reinicia el proceso com.android.shell y, luego, inyecta el código de instrumentación en el proceso para la ejecución de la prueba. Esto también significa que el código de prueba tendrá acceso a todas las instancias de clase que se ejecutan en la aplicación en prueba y podrá manipular el estado según los hooks de prueba expuestos.

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 del módulo, instrucciones de empaquetado y dependencias de tiempo de compilación. En la mayoría de los casos, la opción de archivo de Blueprint basado en Soong es suficiente. Consulta Configuración de prueba simple para obtener más detalles.

Archivo de configuración complejo

Para las pruebas más complejas, también debes escribir un archivo de configuración de pruebas para el marco de pruebas de Android, Trade Federation.

La configuración de la prueba puede especificar opciones especiales de configuración del dispositivo y argumentos predeterminados para proporcionar la clase de prueba.

Se puede acceder a la versión más reciente del archivo de configuración para el cambio de Gerrit de muestra en: frameworks/base/packages/Shell/tests/AndroidTest.xml

Aquí se incluye una instantánea para mayor comodidad:

<configuration description="Runs Tests for Shell.">
    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
        <option name="test-file-name" value="ShellTests.apk" />
    </target_preparer>

    <option name="test-suite-tag" value="apct" />
    <option name="test-tag" value="ShellTests" />
    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
        <option name="package" value="com.android.shell.tests" />
        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
    </test>
</configuration>

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

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

Esto le indica a Trade Federation que instale ShellTests.apk en el dispositivo de destino con un target_preparer especificado. Hay muchos preparadores de destino disponibles para los desarrolladores en Trade Federation, y se pueden usar 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="com.android.shell.tests"/>
  <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
</test>

Esto especifica la clase de prueba de Trade Federation que se usará para ejecutar la prueba y pasa el paquete en el dispositivo que se ejecutará y el framework del ejecutor de pruebas, que es JUnit en este caso.

Consulta aquí para obtener más información sobre Test Module Configs

Funciones de JUnit4

Usar la biblioteca de android-support-test como ejecutor de pruebas permite adoptar nuevas clases de prueba de estilo JUnit4, y el cambio de Gerrit de ejemplo contiene un uso muy básico de sus funciones.

Se puede acceder al código fuente más reciente del cambio de Gerrit de muestra en: frameworks/base/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java

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

@SmallTest
@RunWith(AndroidJUnit4.class)
public final class FeatureFactoryImplTest {

Una diferencia significativa en JUnit4 es que ya no se requiere que las pruebas hereden de una clase de prueba base común. En cambio, escribes pruebas en clases Java simples y usas anotaciones para indicar cierta configuración y restricciones de prueba. En este ejemplo, indicamos que esta clase se debe ejecutar como una prueba de Android JUnit4.

La anotación @SmallTest especificó un tamaño de prueba para toda la clase de prueba: todos los métodos de prueba agregados a esta clase de prueba heredan esta anotación de tamaño de prueba. Configuración previa a la clase de prueba, limpieza posterior a la prueba y limpieza posterior a la clase de prueba: Similar a los métodos setUp y tearDown en JUnit4. La anotación Test se usa para anotar la prueba real.

    @Before
    public void setup() {
    ...
    @Test
    public void testGetProvider_shouldCacheProvider() {
    ...

JUnit4 usa la anotación @Before en los métodos para realizar la configuración previa a la prueba. Aunque no se usa en este ejemplo, también existe @After para la limpieza posterior a la prueba. Del mismo modo, JUnit4 puede usar las anotaciones @BeforeClass y @AfterClass en los métodos para realizar la configuración antes de ejecutar todas las pruebas en una clase de prueba y la desconexión después. Ten en cuenta que los métodos de configuración y desmontaje de alcance de clase deben ser estáticos.

En cuanto a los métodos de prueba, a diferencia de las versiones anteriores de JUnit, ya no es necesario que comiencen con test. En cambio, cada uno de ellos debe estar anotado con @Test. Como de costumbre, los métodos de prueba deben ser públicos, no declarar ningún valor de devolución, no tomar parámetros y pueden arrojar excepciones.

        Context context = InstrumentationRegistry.getTargetContext();

Dado que las pruebas de JUnit4 ya no requieren una clase base común, ya no es necesario obtener instancias de Context a través de getContext() o getTargetContext() a través de métodos de clase base. En cambio, el nuevo ejecutor de pruebas las administra a través de InstrumentationRegistry, donde se almacena la configuración contextual y del entorno creada por el framework de instrumentación. A través de esta clase, también puedes llamar a lo siguiente:

  • getInstrumentation(): Es la instancia de la clase Instrumentation.
  • getArguments(): Los argumentos de la línea de comandos que se pasan a am instrument a través de -e <key> <value>

Compila y prueba de forma local

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

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