Ya está disponible la segunda Vista previa para desarrolladores de Android 11; pruébala y comparte tus comentarios.

Cómo compilar pruebas de unidades locales

Puedes evaluar la lógica de tu app utilizando pruebas de unidades locales si necesitas ejecutar pruebas con mayor rapidez y no precisas la fidelidad y la confianza asociadas con la ejecución de pruebas en un dispositivo real. Con este enfoque, cumples con las relaciones de dependencia utilizando Robolectric o un marco de trabajo ficticio, como Mockito. Por lo general, los tipos de dependencias asociados con las pruebas determinan qué herramienta usar:

  • Si tienes dependencias en el marco de trabajo de Android, en especial, aquellas que crean interacciones complejas, se recomienda incluir dependencias del marco de trabajo usando Robolectric.
  • Si las pruebas tienen dependencias mínimas en el marco de trabajo de Android, o si dependen solo de sus propios objetos, es correcto incluir dependencias ficticias utilizando un marco de trabajo ficticio, como Mockito.

Cómo configurar el entorno de prueba

En el proyecto de Android Studio, debes almacenar los archivos fuente de las pruebas de unidades locales en module-name/src/test/java/. Este directorio ya existe cuando creas un nuevo proyecto.

También debes configurar las dependencias de prueba para que tu proyecto use las API estándar proporcionadas por el marco de trabajo de JUnit 4. Si tu prueba debe interactuar con dependencias de Android, incluye Robolectric o la biblioteca de Mockito para simplificar las pruebas de unidades locales.

En el archivo build.gradle de nivel superior de tu app, especifica las siguientes bibliotecas como dependencias:

    dependencies {
        // Required -- JUnit 4 framework
        testImplementation 'junit:junit:4.12'
        // Optional -- Robolectric environment
        testImplementation 'androidx.test:core:1.0.0'
        // Optional -- Mockito framework
        testImplementation 'org.mockito:mockito-core:1.10.19'
    }
    

Cómo crear una clase de prueba de unidad local

La clase de prueba de unidad local se debe escribir como una clase de prueba JUnit 4. JUnit es el marco de trabajo de prueba de unidades más popular y más usado para Java, y te permite escribir las pruebas de una manera más simple y flexible que las versiones anteriores, ya que con JUnit 4 no es necesario que hagas lo siguiente:

  • Extiendas la clase junit.framework.TestCase.
  • Agregues un prefijo al nombre del método de prueba con la palabra clave 'test'.
  • Uses clases de los paquetes junit.framework o junit.extensions.

Para crear una clase de prueba básica de JUnit 4, crea una clase que contenga uno o más métodos de prueba. Un método de prueba comienza con la anotación @Test y contiene el código para ejercitar y verificar una funcionalidad única en el componente que quieres probar.

En el siguiente ejemplo, se muestra cómo implementar una clase de prueba de unidad local. El método de prueba emailValidator_CorrectEmailSimple_ReturnsTrue verifica que el método isValidEmail() de la app que se prueba muestre el resultado correcto.

Kotlin

    import com.google.common.truth.Truth.assertThat
    import org.junit.Test

    class EmailValidatorTest {
        @Test
        fun emailValidator_CorrectEmailSimple_ReturnsTrue() {
            assertThat(EmailValidator.isValidEmail("name@email.com")).isTrue()
        }
    }
    

Java

    import com.google.common.truth.Truth.assertThat;
    import org.junit.Test;

    public class EmailValidatorTest {
        @Test
        public void emailValidator_CorrectEmailSimple_ReturnsTrue() {
            assertThat(EmailValidator.isValidEmail("name@email.com")).isTrue();
        }
    }
    

Para crear pruebas legibles que evalúen si los componentes de la app muestran los resultados esperados, recomendamos utilizar la biblioteca de Truth y las clases de afirmaciones de Android, como se muestra en el ejemplo anterior. Para obtener más información sobre los tipos de validación lógica que admiten las afirmaciones de Android y Truth, consulta la sección que describe cómo crear afirmaciones más legibles.

Sin embargo, si prefieres comparar los resultados esperados y reales con los métodos Assert o los comparadores de Hamcrest (como los métodos is() y equalTo()), puedes usar esas bibliotecas.

Nota: Hamcrest sigue siendo la biblioteca preferida para usar cuando se crean comparadores, como la clase ViewMatcher de Espresso.

Cómo incluir dependencias en el marco de trabajo

Si tus pruebas interactúan con varias dependencias del marco de trabajo de Android o con esas dependencias de manera compleja, usa los artefactos de Robolectric que proporciona AndroidX Test. Robolectric ejecuta el código del marco de trabajo de Android real y simulaciones del código del marco de trabajo nativo en la JVM local o en un dispositivo real.

En el siguiente ejemplo, se muestra cómo puedes crear una prueba de unidad que use Robolectric:

app/build.gradle

    android {
        // ...
        testOptions {
            unitTests.includeAndroidResources = true
        }
    }
    

MyLocalUnitTestClass

Kotlin

    import android.content.Context
    import androidx.test.core.app.ApplicationProvider
    import com.google.common.truth.Truth.assertThat
    import org.junit.Test

    private const val FAKE_STRING = "HELLO_WORLD"

    class UnitTestSample {
        val context = ApplicationProvider.getApplicationContext<Context>()

        @Test fun readStringFromContext_LocalizedString() {
            // Given a Context object retrieved from Robolectric...
            val myObjectUnderTest = ClassUnderTest(context)

            // ...when the string is returned from the object under test...
            val result: String = myObjectUnderTest.getHelloWorldString()

            // ...then the result should be the expected one.
            assertThat(result).isEqualTo(FAKE_STRING)
        }
    }
    

Java

    import android.content.Context;
    import androidx.test.core.app.ApplicationProvider;
    import org.junit.Test;

    import static com.google.common.truth.Truth.assertThat;

    public class UnitTestSampleJava {
        private static final String FAKE_STRING = "HELLO_WORLD";
        private Context context = ApplicationProvider.getApplicationContext();

        @Test
        public void readStringFromContext_LocalizedString() {
            // Given a Context object retrieved from Robolectric...
            ClassUnderTest myObjectUnderTest = new ClassUnderTest(context);

            // ...when the string is returned from the object under test...
            String result = myObjectUnderTest.getHelloWorldString();

            // ...then the result should be the expected one.
            assertThat(result).isEqualTo(FAKE_STRING);
        }
    }
    

Cómo incluir clases de Android Builder

Si creas pruebas de unidades locales que ejecutas en un entorno de Robolectric o en un dispositivo real, puedes usar los creadores que proporciona AndroidX Test para varias clases de marcos de trabajo comunes. Estos creadores te permiten generar instancias de las siguientes clases sin necesidad de usar ubicaciones ficticias ni reflejos:

Cómo usar la clase de utilidad Parcelables

Además, la biblioteca proporciona una clase de utilidad para objetos Parcelable. Cuando proporcionas un objeto Creator, esta clase deserializa el objeto Parcelable específico y, luego, serieliza el objeto Parcelable duplicado.

Nota: Corresponde al método que llama a Parcelables.forceParcel() para verificar que la operación de deserializar/volver a serializar sea correcta.

Cómo incluir dependencias ficticias

De manera predeterminada, el complemento de Android para Gradle ejecuta las pruebas de unidades locales en una versión modificada de la biblioteca android.jar, que no contiene ningún código real. En cambio, las llamadas del método a las clases de Android desde la prueba de unidades generan una excepción. Esto es para asegurarte de que probarás solo el código y que no dependerás de ningún comportamiento particular de la plataforma de Android (que no has compilado o para el que no has generado ubicaciones ficticias explícitamente).

Cómo generar dependencias ficticias de Android

Si tienes dependencias mínimas de Android y necesitas probar interacciones específicas entre un componente y su dependencia dentro de tu app, usa un marco de trabajo ficticio con el fin de eliminar las dependencias externas del código. De esta manera, puedes probar fácilmente que el componente interactúa con la dependencia de la manera esperada. Al sustituir las dependencias de Android con objetos ficticios, puedes aislar la prueba de unidad del resto del sistema Android mientras verificas que se llame a los métodos correctos en esas dependencias. El marco de trabajo ficticio de Mockito para Java (versión 1.9.5 y posteriores) ofrece compatibilidad con las pruebas de unidades de Android. Con Mockito, puedes configurar objetos ficticios para mostrar algún valor específico cuando se invoca.

Para agregar un objeto ficticio a la prueba de unidad local utilizando este marco de trabajo, sigue este modelo de programación:

  1. Incluye la dependencia de la biblioteca de Mockito en el archivo build.gradle, como se describe en Cómo configurar el entorno de prueba.
  2. Al comienzo de la definición de la clase de prueba de la unidad, agrega la anotación @RunWith(MockitoJUnitRunner.class). Ese objeto le indica al panel de pruebas de Mockito que valide que tu uso del marco de trabajo es correcto y simplifica la inicialización de tus objetos ficticios.
  3. Con el fin de crear un objeto ficticio para una dependencia de Android, agrega la anotación @Mock antes de la declaración del campo.
  4. Para indicar el comportamiento de la dependencia, puedes especificar una condición y mostrar un valor cuando se cumpla con la condición mediante los métodos when() y thenReturn().

En el siguiente ejemplo, se muestra cómo puedes crear una prueba de unidad que utilice un objeto Context ficticio.

Kotlin

    import android.content.Context
    import com.google.common.truth.Truth.assertThat
    import org.junit.Test
    import org.junit.runner.RunWith
    import org.mockito.Mock
    import org.mockito.Mockito.`when`
    import org.mockito.junit.MockitoJUnitRunner

    private const val FAKE_STRING = "HELLO WORLD"

    @RunWith(MockitoJUnitRunner::class)
    class UnitTestSample {

        @Mock
        private lateinit var mockContext: Context

        @Test
        fun readStringFromContext_LocalizedString() {
            // Given a mocked Context injected into the object under test...
            `when`(mockContext.getString(R.string.hello_word))
                    .thenReturn(FAKE_STRING)
            val myObjectUnderTest = ClassUnderTest(mockContext)

            // ...when the string is returned from the object under test...
            val result: String = myObjectUnderTest.getHelloWorldString()

            // ...then the result should be the expected one.
            assertThat(result, `is`(FAKE_STRING))
        }
    }
    

Java

    import android.content.Context;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mock;
    import org.mockito.junit.MockitoJUnitRunner;

    import static com.google.common.truth.Truth.assertThat;
    import static org.mockito.Mockito.when;

    @RunWith(MockitoJUnitRunner.class)
    public class UnitTestSample {

        private static final String FAKE_STRING = "HELLO WORLD";

        @Mock
        Context mockContext;

        @Test
        public void readStringFromContext_LocalizedString() {
            // Given a mocked Context injected into the object under test...
            when(mockContext.getString(R.string.hello_world))
                    .thenReturn(FAKE_STRING);
            ClassUnderTest myObjectUnderTest = new ClassUnderTest(mockContext);

            // ...when the string is returned from the object under test...
            String result = myObjectUnderTest.getHelloWorldString();

            // ...then the result should be the expected one.
            assertThat(result, is(FAKE_STRING));
        }
    }
    

Para obtener más información sobre el uso del marco de trabajo de Mockito, consulta la referencia de la API de Mockito y la clase SharedPreferencesHelperTest en el código de muestra. Prueba también Android Testing Codelab.

Error: "Método… no ficticio"

Si ejecutas una prueba que llama a una API desde el SDK de Android que no es ficticia, se mostrará un error que indica que este método no es ficticio. El motivo es que el archivo android.jar usado para ejecutar pruebas de unidades no contiene ningún código (esas API solo las proporciona la imagen del sistema Android en un dispositivo).

En cambio, todos los métodos muestran excepciones de forma predeterminada. La finalidad es asegurarte de que las pruebas de unidades solo prueben tu código y no dependan de ningún comportamiento particular de la plataforma de Android (para el que no has generado una ubicación ficticia explícitamente, por ejemplo, con Mockito).

Si las excepciones generadas son problemáticas para las pruebas, puedes cambiar el comportamiento para que, en su lugar, los métodos muestren un valor nulo o equivalente a cero agregando la siguiente configuración en el archivo build.gradle de nivel superior del proyecto:

    android {
      ...
      testOptions {
        unitTests.returnDefaultValues = true
      }
    }
    

Precaución: Ten cuidado si estableces la propiedad returnDefaultValues como true. Los valores de nulo/cero que se muestran pueden introducir regresiones en las pruebas, que son difíciles de depurar y pueden permitir que se aprueben las pruebas fallidas. Úsalo solo como último recurso.

Cómo ejecutar pruebas de unidades locales

Para ejecutar pruebas de unidades locales, sigue estos pasos:

  1. Asegúrate de que tu proyecto esté sincronizado con Gradle. Para ello, haz clic en la opción Sync Project de la barra de herramientas.
  2. Ejecuta tu prueba de una de las siguientes maneras:
    • Para ejecutar una sola prueba, abre la ventana Project y, a continuación, haz clic con el botón derecho en una prueba y, luego, haz clic en Run .
    • Para probar todos los métodos de una clase, haz clic con el botón derecho en una clase o método en el archivo de prueba y luego haz clic en Run .
    • Para ejecutar todas las pruebas de un directorio, haz clic con el botón derecho en el directorio y selecciona Run tests .

El complemento de Android para Gradle compila el código de prueba de unidades locales ubicado en el directorio predeterminado (src/test/java/), compila una app de prueba y la ejecuta localmente utilizando la clase de panel de prueba predeterminado. Android Studio luego muestra los resultados en la ventana Run.