Cómo automatizar las pruebas de IU

Probar las interacciones de los usuarios ayuda a garantizar que no encuentren resultados inesperados ni tengan una mala experiencia cuando interactúen con tu app. Debes adquirir el hábito de crear pruebas de interfaz de usuario (IU) si necesitas verificar que la IU de tu app funciona correctamente.

Un enfoque para las pruebas de IU es simplemente hacer que un verificador humano realice un conjunto de operaciones del usuario en la app de destino y verifique que se comporte de forma correcta. Sin embargo, este enfoque manual puede llevar mucho tiempo y generar errores. Un enfoque más eficiente es escribir las pruebas de la IU de modo que las acciones del usuario se realicen de manera automatizada. El enfoque automatizado te permite ejecutar las pruebas de forma rápida y confiable de manera repetible.

Las pruebas de la IU inician una app (o parte de ella), simulan las interacciones del usuario y, por último, comprueban que la app reaccionó de forma adecuada. Son pruebas de integración que pueden variar desde la verificación del comportamiento de un componente pequeño hasta una prueba de navegación grande que recorre un flujo de usuarios completo. Son útiles para comprobar la existencia de regresiones y la compatibilidad con diferentes niveles de API y dispositivos físicos.

Pruebas de IU instrumentadas en Android Studio

Para ejecutar pruebas de IU instrumentadas con Android Studio, implementa el código de prueba en una carpeta de pruebas de Android separada: src/androidTest/java. El complemento de Android para Gradle compila una app de prueba basada en el código de prueba y, luego, carga la app de prueba en el mismo dispositivo que la app de destino. En tu código de prueba, puedes usar frameworks de prueba de IU para simular las interacciones de un usuario en la app de destino a fin de realizar tareas de prueba que abarcan situaciones de uso específicas.

Frameworks de Jetpack

Jetpack incluye varios frameworks que proporcionan APIs para escribir pruebas de IU:

  • El framework de prueba de Espresso (Android 4.0.1, nivel de API 14 o versiones posteriores) proporciona APIs para escribir pruebas de IU que simulan las interacciones del usuario con Views dentro de una sola app de destino. Un beneficio clave de usar Espresso es que proporciona una sincronización automática de las acciones de prueba con la IU de la app que estás probando. Espresso detecta cuando el subproceso principal está inactivo, por lo que puede ejecutar los comandos de prueba en el momento adecuado, lo que mejora la confiabilidad de las pruebas.
  • Jetpack Compose (Android 5.0, nivel de API 21 o versiones posteriores) proporciona un conjunto de APIs de prueba para iniciar pantallas y componentes de Compose e interactuar con ellos. Las interacciones con elementos de Compose se sincronizan con pruebas y tienen control completo sobre el tiempo, las animaciones y las recomposiciones.
  • UI Automator (Android 4.3, nivel de API 18 o versiones posteriores) es un framework de pruebas de IU adecuado para pruebas de IU funcionales entre apps en el sistema y las apps instaladas. Las APIs de UI Automator te permiten realizar operaciones como abrir el menú Configuración o el selector de aplicaciones en un dispositivo de prueba.
  • Robolectric (Android 4.1, nivel de API 16 o versiones posteriores) te permite crear pruebas locales que se ejecutan en tu estación de trabajo o entorno de integración continua en una JVM normal, en lugar de hacerlo en un emulador o dispositivo. Puede usar las APIs de prueba de Espresso o Compose para interactuar con los componentes de la IU.

Inconsistencia y sincronización

La naturaleza asíncrona de las aplicaciones y frameworks para dispositivos móviles suele dificultar la escritura de pruebas confiables y repetibles. Cuando se inserta un evento de usuario, el framework de pruebas debe esperar a que la app termine de reaccionar, lo que puede variar desde cambiar texto en pantalla hasta recreación completa de una actividad. Cuando una prueba no tiene un comportamiento determinista, es frágil.

Los frameworks modernos, como Compose o Espresso, se diseñaron teniendo en cuenta las pruebas, por lo que hay cierta garantía de que la IU estará inactiva antes de la siguiente acción o aserción de prueba. Esto se llama sincronización.

Probar la sincronización

Pueden surgir problemas cuando ejecutas operaciones asíncronas o en segundo plano desconocidas para la prueba, como cargar datos desde una base de datos o mostrar animaciones infinitas.

diagrama de flujo en el que se muestra un bucle que verifica si la app está inactiva antes de realizar una prueba aprobada
Figura 1: Sincronización de prueba.

Para aumentar la confiabilidad de tu conjunto de pruebas, puedes instalar una forma de realizar un seguimiento de las operaciones en segundo plano, como los recursos de inactividad de Espresso. Además, puedes reemplazar módulos para probar versiones que puedes consultar por inactividad o que mejoran la sincronización, como TestDispatcher para corrutinas o RxIdler para RxJava.

Diagrama que muestra una falla de prueba cuando la sincronización se basa en esperar un tiempo fijo
Figura 2: El uso de datos de sueño en las pruebas hace que las pruebas sean lentas o inestables.

Arquitectura y configuración de pruebas

La arquitectura de tu app debe permitir que las pruebas reemplacen partes para probar dobles, y debes usar bibliotecas que proporcionen utilidades para ayudar con las pruebas. Por ejemplo, puedes reemplazar un módulo de repositorio de datos por una versión en la memoria de este que proporciona datos deterministas falsos a la prueba.

Diagramas de arquitectura de producción y pruebas En el diagrama de producción, se muestran fuentes de datos locales y remotas que proporcionan datos al repositorio, que, a su vez, los proporciona de forma asíncrona a la IU. En el diagrama de prueba, se muestra un repositorio falso que proporciona sus datos a la IU de manera síncrona.
Figura 3: Prueba de una IU mediante el reemplazo de sus dependencias con emulaciones.

El enfoque recomendado para habilitar esta funcionalidad es utilizar la inserción de dependencias. Puedes crear tu propio sistema manualmente, pero te recomendamos que uses un framework de DI como Hilt para esto.

¿Por qué probar automáticamente?

Una app para Android puede orientarse a miles de dispositivos diferentes en muchos niveles de API y factores de forma, y el alto nivel de personalización que el SO brinda al usuario significa que tu app podría procesarse de forma incorrecta o incluso fallar en algunos dispositivos.

Las pruebas de IU te permiten realizar pruebas de compatibilidad, que verifican el comportamiento de una app en diferentes contextos. Te recomendamos que ejecutes las pruebas de IU en dispositivos que varían de las siguientes maneras:

  • Nivel de API: 21, 25 y 30.
  • Configuración regional: Inglés, árabe y chino.
  • Orientación: Vertical, horizontal.

Además, las apps deben comprobar el comportamiento más allá de los teléfonos. Deberías realizar pruebas en tablets, dispositivos plegables y otros dispositivos.

Recursos adicionales

Para obtener más información sobre cómo crear pruebas de IU, consulta los siguientes recursos.

Documentación

Codelabs