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.
- Navega a la página de repositorio de GitHub del proyecto.
- 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.
- En la página de GitHub de este proyecto, haz clic en el botón Code, el cual abre una ventana emergente.
- 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.
- Ubica el archivo en tu computadora (probablemente en la carpeta Descargas).
- 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
- Inicia Android Studio.
- En la ventana Welcome to Android Studio, haz clic en Open.
Nota: Si Android Studio ya está abierto, selecciona la opción de menú File > Open.
- En el navegador de archivos, ve hasta donde se encuentra la carpeta del proyecto descomprimida (probablemente en Descargas).
- Haz doble clic en la carpeta del proyecto.
- Espera a que Android Studio abra el proyecto.
- Haz clic en el botón Run 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.
- 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.
- La vista de tu proyecto tendrá el siguiente aspecto:
- Haz clic en el primer menú desplegable y navega hasta app -> src.
- Haz clic con el botón derecho en src y selecciona New -> Directory.
- Debería aparecer esta ventana:
- Selecciona androidTest/java.
- Ahora verás el directorio androidTest en la estructura del proyecto.
- Haz clic con el botón derecho en el directorio java y selecciona New -> Package.
- Verás la ventana resultante:
- En la ventana, escribe el texto a continuación y presiona Return:
com.example.tiptime
- La ventana de tu proyecto debería verse de la siguiente manera:
- Por último, haz clic con el botón derecho en com.example.tiptime y selecciona New -> Kotlin Class/File.
- 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%.
- Abre el archivo que acabas de crear. Debería verse así:
package com.example.tiptime
class CalculatorTests {
}
- 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.
- 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 claseCalculatorTests
.
@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.
- 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.
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.
- El primer paso es buscar un componente de la IU con el que interactuar, en este caso,
TextInputEditText
, mediante la funciónonView()
. La funciónonView()
toma un parámetro de objetoViewMatcher
. 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 IDR.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())
- 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 queViewAction
es diferente. En lugar detypeText()
, se usa la funciónclick()
.
onView(withId(R.id.calculate_button))
.perform(click())
- 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 IDtip_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.
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.