Cómo escribir pruebas de instrumentación

1. Antes de comenzar

En un codelab anterior, aprendiste a crear y ejecutar pruebas de unidades. Este codelab se enfoca en las pruebas de instrumentación. Tendrás la oportunidad de ver su aspecto y la forma de escribirlas.

Requisitos previos

  • Haber creado un proyecto en Android Studio
  • Tener cierta experiencia en la escritura de código en Android Studio
  • Tener cierta experiencia en la navegación de proyectos en Android Studio
  • Haber escrito pruebas de unidades simples en Android Studio

Qué aprenderás

  • Cómo se ven las pruebas de instrumentación
  • Cómo ejecutar pruebas de instrumentación
  • Cómo escribir pruebas de instrumentación

Requisitos

  • Una computadora que tenga Android Studio instalado
  • El código de la solución de la app de Tip Time

Descarga el código de partida para este codelab

En este codelab, agregarás pruebas de instrumentación a la app de Tip Time desde un código de solución anterior.

  1. Navega a la página de repositorio de GitHub del proyecto.
  2. Verifica que el nombre de la rama coincida con el especificado en el codelab. Por ejemplo, en la siguiente captura de pantalla, el nombre de la rama es main.

1e4c0d2c081a8fd2.png

  1. En la página de GitHub de este proyecto, haz clic en el botón Code, el cual abre una ventana emergente.

1debcf330fd04c7b.png

  1. En la ventana emergente, haz clic en el botón Download ZIP para guardar el proyecto en tu computadora. Espera a que se complete la descarga.
  2. Ubica el archivo en tu computadora (probablemente en la carpeta Descargas).
  3. Haz doble clic en el archivo ZIP para descomprimirlo. Se creará una carpeta nueva con los archivos del proyecto.

Abre el proyecto en Android Studio

  1. Inicia Android Studio.
  2. En la ventana Welcome to Android Studio, haz clic en Open.

d8e9dbdeafe9038a.png

Nota: Si Android Studio ya está abierto, selecciona la opción de menú File > Open.

8d1fda7396afe8e5.png

  1. En el navegador de archivos, ve hasta donde se encuentra la carpeta del proyecto descomprimida (probablemente en Descargas).
  2. Haz doble clic en la carpeta del proyecto.
  3. Espera a que Android Studio abra el proyecto.
  4. Haz clic en el botón Run 8de56cba7583251f.png para compilar y ejecutar la app. Asegúrate de que funcione como se espera.

2. Descripción general de la app de partida

La app de Tip Time consta de una pantalla que le muestra al usuario una entrada de texto para ingresar un importe de factura, botones de selección para elegir un porcentaje de propina y un botón para calcular la propina.

3. Cómo crear el directorio de la prueba de instrumentación

El código de partida para este codelab es completamente funcional, pero carece de pruebas y de directorios de pruebas. Antes de escribir pruebas de cualquier tipo, debemos agregar un directorio para las pruebas de instrumentación. Una vez que hayas descargado el código de partida, sigue estos pasos para agregar una clase para tus pruebas de instrumentación.

  1. La manera más fácil de hacerlo es cambiar primero de la vista Android a la vista Project. En el panel del proyecto ubicado en la parte superior izquierda, haz clic en el menú desplegable que dice Android y selecciona Project.

20055afdc5d38e69.png

  1. La vista de tu proyecto tendrá el siguiente aspecto:

7e933e8dd546458e.png

  1. Haz clic en el primer menú desplegable y navega hasta app -> src.

65dd6a80920623ef.png

  1. Haz clic con el botón derecho en src y selecciona New -> Directory.

73b014c84f89b0f0.png

  1. Debería aparecer esta ventana:

921d8a0df6310383.png

  1. Selecciona androidTest/java.

c4b99c44611ae609.png

  1. Ahora verás el directorio androidTest en la estructura del proyecto.

5f6643d80a7ef0f8.png

  1. Haz clic con el botón derecho en el directorio java y selecciona New -> Package.

8f8a590b7bdc01b3.png

  1. Verás la ventana resultante:

4d154746de968ccf.png

  1. En la ventana, escribe el texto a continuación y presiona Return:
com.example.tiptime
  1. La ventana de tu proyecto debería verse de la siguiente manera:

7bb036a4bc3be441.png

  1. Por último, haz clic con el botón derecho en com.example.tiptime y selecciona New -> Kotlin Class/File.

26ff162c120e18d1.png

  1. En la ventana resultante, escribe CalculatorTests, selecciona Class en el menú desplegable y presiona Return.

4. Cómo escribir tu primera prueba de instrumentación

Ahora es el momento de escribir una prueba de instrumentación. En los siguientes pasos, se prueba la funcionalidad para obtener una propina del 20%.

  1. Abre el archivo que acabas de crear. Debería verse así:
package com.example.tiptime

class CalculatorTests {
}
  1. Las pruebas de instrumentación requieren un InstrumentationTestRunner, que permite que la prueba se ejecute en un dispositivo o emulador. Existen muchos otros ejecutores de instrumentación, pero para esta prueba usaremos el ejecutor de pruebas AndroidJUnit4. Para especificar el ejecutor de pruebas, debemos anotar la clase con lo siguiente:
@RunWith(AndroidJUnit4::class)
class CalculatorTests {
}

Por si acaso, estas son las importaciones que necesitas:

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith

Ahora, todo está configurado para comenzar a escribir la lógica de prueba.

  1. La app de Tip Time consta de una sola actividad, MainActivity. Para interactuar con la actividad, tu caso de prueba primero debe iniciarla. Agrega lo siguiente dentro de la clase CalculatorTests.
@get:Rule()
val activity = ActivityScenarioRule(MainActivity::class.java)

ActivityScenarioRule proviene de la biblioteca de prueba de AndroidX. Le indica al dispositivo que inicie una actividad especificada por el desarrollador. Deberás anotarla con @get:Rule, que especifica que la regla posterior, en este caso, iniciar una actividad, debe ejecutarse antes de cada prueba de la clase. Las reglas de prueba son una herramienta fundamental para realizar pruebas y, con el tiempo, aprenderás a escribir la tuya.

  1. A continuación, debes escribir la lógica de prueba. Crea una función, llámala calculate_20_percent_tip() y anótala con la anotación @Test.
@Test
fun calculate_20_percent_tip() {
}

Espresso

Este curso usa más que nada Espresso para pruebas de instrumentación. Espresso es una biblioteca que está lista para usarse con un proyecto de Android cuando se crea con Android Studio, y te permite interactuar con los componentes de la IU a través de código.

En este punto, tal vez hayas notado que Android Studio tiene muchas funciones de autocompletado. Uno de los aspectos desafiantes de trabajar con Espresso es que los métodos no se autocompletan si no se importó la biblioteca. Esto puede dificultar la navegación por los métodos disponibles en Espresso sin consultar la documentación. A lo largo de estas lecciones, te proporcionaremos los métodos necesarios para completar las pruebas.

Primero, debes escribir el código para ingresar el importe de la factura en la vista de texto de entrada Cost of Service. Si navegas a app -> src -> main -> res -> layout > activity_main.xml, verás que el ID de TextInputEditText es cost_of_service_edit_text. Copia el nombre del ID, que necesitaremos más adelante para la prueba.

a113fb63b50f7674.png

Cómo implementar la función de prueba

Ahora, en la función calculate_20_percent_tip() de tu clase de prueba, puedes escribir la lógica de prueba.

  1. El primer paso es buscar un componente de la IU con el que interactuar, en este caso, TextInputEditText, mediante la función onView(). La función onView() toma un parámetro de objeto ViewMatcher. En esencia, ViewMatcher es un componente de IU que coincide con un criterio en particular, que en este caso es un componente que tiene el ID R.id.cost_of_service_edit_text.

La función withId() devuelve ViewMatcher, que es el componente de la IU con el ID que se le pasa. onView() devuelve ViewInteraction, que es un objeto con el que podemos interactuar como si estuviéramos controlando el dispositivo. Para ingresar texto, llama a perform() en ViewInteraction. Luego, perform() toma un objeto ViewAction. Hay varios métodos que devuelven ViewAction, pero, por ahora, usaremos el método typeText(). En activity_main.xml, podemos ver que la opción de propina predeterminada es del 20%. Por el momento, no es necesario que especifiques la opción de propina para seleccionar.

onView(withId(R.id.cost_of_service_edit_text))
    .perform(typeText("50.00"))

Luego, toda la instrucción se vería de la siguiente manera:

onView(withId(R.id.cost_of_service_edit_text))
    .perform(typeText("50.00"))
    .perform(ViewActions.closeSoftKeyboard())
  1. De esta forma, se ingresará el texto y la prueba deberá hacer clic en el botón Calculate. El código correspondiente tiene un formato similar al que usamos para ingresar texto. El componente de la IU es diferente, por lo que el nombre del ID que se pasa a la función withId() es diferente. Sin embargo, la única diferencia en el enfoque es que ViewAction es diferente. En lugar de typeText(), se usa la función click().
onView(withId(R.id.calculate_button))
    .perform(click())
  1. Por último, debes realizar la aserción de que se muestra la propina correcta. Esperamos que el importe de la propina sea USD 10. Para esta prueba, asegúrate de que TextView con el ID tip_result contenga el valor de la propina esperado en forma de cadena.
onView(withId(R.id.tip_result))
    .check(matches(withText(containsString("$10.00"))))

Selecciona las siguientes importaciones cuando se te solicite:

import androidx.test.espresso.assertion.ViewAssertions.matches
import org.hamcrest.Matchers.containsString

Aquí, usaste una interacción diferente llamada check(), que toma un elemento ViewAssertion. Considera que ViewAssertion es una aserción especial de Espresso que se usa para los componentes de IU. La aserción es que el contenido de TextView coincide con el texto que contiene la string "$10.00".

Antes de ejecutar la prueba, asegúrate de que tus importaciones y el código sean correctos; deberían verse de la siguiente manera (no hay problema si tus importaciones están en un orden diferente):

package com.example.tiptime

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.Matchers.containsString
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class CalculatorTests {

   @get:Rule()
   val activity = ActivityScenarioRule(MainActivity::class.java)

   @Test
   fun calculate_20_percent_tip() {
       onView(withId(R.id.cost_of_service_edit_text))
           .perform(typeText("50.00"))

       onView(withId(R.id.calculate_button)).perform(click())

       onView(withId(R.id.tip_result))
           .check(matches(withText(containsString("$10.00"))))
   }
}

Si usas un emulador, asegúrate de que puedas ver tanto el emulador como la ventana de Android Studio al mismo tiempo. Ejecuta la prueba de la misma manera que ejecutas las pruebas de unidades (haz clic con el botón derecho en el botón de flecha roja/verde a la izquierda de la función y selecciona la primera opción) y observa lo que sucede.

36684dfa8a17a2c9.gif

Puedes ver que la prueba se ejecuta como si alguien estuviera interactuando con la app.

5. Cómo expandir tu paquete de pruebas

¡Felicitaciones! Lograste que tu primera prueba de instrumentación funcionara.

Si te interesa el desafío, puedes expandir el paquete de pruebas. Para ello, agrega funciones que prueben los otros porcentajes de propina. Usa el mismo formato que el de la función que escribimos antes. El único cambio que debes hacer es escribir el código para seleccionar una opción de porcentaje diferente y cambiar el valor que se pasó a containsString() para dar cuenta de los diferentes resultados esperados. No olvides que también hay una opción de redondeo. Para activar o desactivar el interruptor de redondeo hacia arriba, busca el componente por su ID, como se demostró con onView(withId()), y haz clic en él.

6. Código de solución

7. Resumen

  • Android Studio genera las clases de prueba necesarias cuando se crea el proyecto. Sin embargo, si encuentras un proyecto que no las tiene, puedes crearlas de forma manual.
  • Las reglas de prueba se ejecutan antes de cada prueba en una clase de prueba.
  • Espresso es un componente fundamental de las pruebas de instrumentación. Permite la interacción con componentes de la IU mediante código.

Esta fue una lección extensa. Felicitaciones por tu trabajo.

Más información