UI Testing con EarlGrey2: Parte 1

Bastián Véliz
Concrete Latinoamérica
8 min readMay 27, 2020

Esta es una serie de artículos relacionados a como realizar pruebas de UI utilizando EarlGrey2. En esta primera parte se aborda la instalación y configuración de la biblioteca en un proyecto.

El resto de artículos los puedes encontrar acá:

Mi viejo amigo ya no es lo que era

Hace unos años atrás, me tocó dar una pequeña charla acerca de cómo realizar UI Testing usando EarlGrey, una herramienta creada por Google. Ésta era usada internamente para hacer UI Testing de sus aplicaciones y fue liberada como proyecto de código abierto para que así toda la comunidad pudiese usarla. En su momento ofrecía algo realmente prometedor:

  • Una serie de matchers con soporte para verificar automáticamente la visibilidad de una vista o elemento en pantalla, espera automática de peticiones de red, scroll automático, entre otros.
  • Realizar test de caja blanca haciendo interacciones con la interfaz de usuario como una prueba de UI, pero en un target de pruebas unitarias.
  • Debido a lo anterior, podías acceder a todas las clases del proyecto y por ende realizar inyección de dependencias en tiempo de ejecución.
UI Testing EarlGrey (1) — Mi yo joven

En mi caso particular, una de las cosas que hacía que eligiera EarlGrey por sobre otras alternativas era su estabilidad y consistencia al correr pruebas en entornos de integración continua, algo que con XCUITest no podía conseguir (afortunadamente, esos problemas han sido subsanados en las recientes versiones). Sin embargo, de los problemas más recurrentes que tenía con esta herramienta el más importante fue la demora en soportar nuevas versiones de iOS. Cada vez que salía una nueva versión algunas pruebas se rompían y pasaba un tiempo no menor esperando la corrección, que a veces llegaba y a veces no. Todo bien hasta aquí… de no ser por iOS 13.

Muchos usuarios han reportado fallos al intentar correr sus pruebas creadas con EarlGrey en iOS 13. En la sección de Issues en su repositorio de Github se pueden apreciar múltiples reportes y en varios de ellos la respuesta es la misma: debes usar EarlGrey 2.

EarlGrey 2 y sus cambios

EarlGrey2 es un cambio sustancial en la forma en la que se realizan las pruebas y cómo las interacciones se llevan a cabo. Pero, ¿qué es lo tan diferente? Pues la verdad es que… varias cosas. Vamos por partes:

  • En primer lugar, EarlGrey 2 corre en pruebas que utilizan XCUITest. Por ende, correr las pruebas en un target de pruebas unitarias está descartado.
  • Para realizar las interacciones en la interfaz de usuario EarlGrey 2 utiliza un sofisticado sistema de invocaciones, gracias a otra biblioteca de Google: eDistantObject.
Funcionamiento de EarlGrey 2 — Google
  • La documentación de la biblioteca aún está en pañales y repartida entre las numerosas ramas que tiene el proyecto en Github, por lo que hay que armarse de paciencia y sobre todo estar dispuesto a tropezarse en el camino.

Otro punto muy relevante es cómo se compone EarlGrey 2, debido a que son 4 bibliotecas que interactúan entre sí. Estos son:

  • CommonLib, el cuál contiene funciones que son utilizadas de forma transversal.
  • UILib, que contiene funciones utilizadas para realizar verificaciones en la interfaz de usuario.
  • TestLib, que contiene funciones utilizadas en entornos de pruebas y que además posee las configuraciones que utilizan eDistantObject.
  • AppFramework, que contiene funciones que son usadas para realizar la interacción con la interfaz de usuario y también para comunicarse con TestLib usando eDistantObject.
Componentes de EarlGrey 2 — Google

Como se muestra en la imagen anterior, estas bibliotecas se agrupan en dos grandes componentes, TestComponent y AppComponent. El primero debe ser agregado en el target de pruebas de UI y el segundo, en cambio, debe ser agregado a la aplicación principal.

Si bien son muchos cambios con respecto a su versión anterior, un punto muy relevante para mi es que la configuración para pruebas de caja negra y caja blanca cambia bastante. Esto se debe a que:

  • Para el primer caso, la configuración es casi gratis si usas un proyecto con Cocoapods, ya que agregas los pods como nuevas dependencias y tienes acceso a todas las clases sin mayores complicaciones.
  • Por otro lado, configurar EarlGrey 2 para pruebas de caja blanca no es trivial. De momento no hay soporte para Cocoapods o algún otro gestor de dependencias, es decir, hay que agregar todo “a mano”. Además, es un requisito habilitar el soporte para pruebas pruebas de caja negra, lo que requiere seguir una serie de pasos para agregar variables, importar cabeceras e importar bibliotecas en donde es muy fácil equivocarse. En resumen, hay que hacer todo desde cero y armarnos de paciencia.

Debido a todo lo anterior a lo largo de este artículo intentaré hacer un paso a paso que sea detallado y a prueba de errores (ojalá) para poder aprovechar todos los beneficios de EarlGrey 2 y llevar las pruebas de UI al siguiente nivel. ¡Comencemos!

Configurando EarlGrey 2 para pruebas de caja negra

Proyecto inicial

El proyecto que utilizaremos en toda esta guía consiste en una aplicación con las siguientes características:

  • Puedes buscar un artista o una canción y obtener una lista de las posibles coincidencias.
  • Al seleccionar un elemento de la lista, puedes ver un poco más sobre el elemento seleccionado.
  • Para obtener toda la información, utilizo la iTunes Store API.
SwiftUI y el modo oscuro se llevan muy bien :)

La interfaz de usuario fue construida usando SwiftUI y para la descarga / almacenamiento de imágenes utilicé SDWebImageSwiftUI.

Puedes revisar todo él código de la aplicación en Github. El proyecto inicial se encuentra en la rama initial-project.

Obtener EarlGrey 2

En primer lugar debemos clonar el repositorio de EarlGrey 2 como submódulo de git. Para ello, en el directorio raíz de nuestro repositorio ejecutamos:

git submodule add -b earlgrey2 https://github.com/google/EarlGrey.git ItunesSimpleSearch/EarlGrey2

Luego, debemos obtener las dependencias de EarlGrey 2. Para ello, siguiendo en el directorio raíz, ejecutamos los siguientes comandos:

cd ItunesSimpleSearch/EarlGrey2/
sh Scripts/download_deps.sh

Con esto, se creará una carpeta llamada Submodules, la cual contiene 2 carpetas eDistantObject y fishhook:

ls -lh Submodules
total 0
drwxr-xr-x 18 bastian staff 576B May 22 20:21 eDistantObject
drwxr-xr-x 10 bastian staff 320B May 22 20:21 fishhook

Es muy importante ejecutar el script download_deps.sh desde la carpeta EarlGrey2 y no en la carpeta Scripts, sino el proyecto de XCode no detectará esas dependencias y tus compilaciones fallarán.

Finalmente, para verificar que todo salió bien, abre el proyecto EarlGrey.xcodeproj y compila el esquema AppFramework. Si compila bien, podemos pasar a la siguiente etapa.

Compilando AppFramework — Verificando que todo salió bien

Integrando EarlGrey2 a nuestro proyecto

Ya teniendo descargado EarlGrey 2 y sus dependencias vamos a agregar el proyecto a nuestro proyecto base. Para ello debemos abrir el archivo ItunesSimpleSearch.xcworkspace y arrastrar el proyecto de EarlGrey al nuestro. Debería quedar así:

Proyecto EarlGrey integrado

Integrando Test Component

¿Recuerdan en donde les mencioné los dos componentes principales de EarlGrey 2? Pues el siguiente paso que debemos realizar es integrar ambos a nuestro proyecto partiendo por el Test Component, lo cual se debe realizar en el target de UI Tests. Para ello seguiré las instrucciones que podemos encontrar en la documentación y las aplicaré para este proyecto con algunos cambios.

  • En primer lugar, debemos ir a la sección Build Phases del target ItunesSimpleSearchUITests y agregar el elemento libTestLib.a
Agregando libTestLib.a.

Si aparece una alerta diciendo “File is already being linked.”, seleccionen “Add Anyway”.

  • Luego, debemos ir a la sección Build Settings y agregar -ObjC en la sección Other Linker Flags del mismo target.
Agregando -ObjC en Other Linker Flags
  • Finalmente, debemos agregar las siguientes variables en la sección User Header Search Paths seleccionando recursive:
$(SRCROOT)/EarlGrey2
$(SRCROOT)/EarlGrey2/Submodules/eDistantObject

Acá hay que hacer mención a que en la documentación oficial no sale de forma clara como se deberían agregar estas cabeceras. Sin embargo, con esas dos entradas incluimos todas las cabeceras que se deben exponer.

Agregando elementos a User Header Search Path

Si en este punto pensabas que todo está listo… Emmm no. Porque si intentas correr todas las pruebas (usando Cmd + U por ejemplo) obtendrás el siguiente fallo:

Cuando todo debería funcionar — pero no

Para solucionarlo, debemos pasar a la siguiente fase.

Integrando App Component

Como describí más arriba, EarGrey2 funciona debido a la interacción entre Test Component y App Component. Si bien dije que App Component se debe integrar en la aplicación, todos estos pasos los tenemos que hacer en el target de pruebas de UI, es decir en ItunesSimpleSearchUITests.

¿Pero no que esto se agregaba en la aplicación principal? Sí, pero de una forma especial: Al momento de compilar el target de pruebas de UI se copia una de las bibliotecas de EarlGrey, AppFramework, al binario de la aplicación principal. Luego, al lanzarse la aplicación, esta biblioteca es cargada dinámicamente en tiempo de ejecución. Una maravilla.

Pues bien, para integrar App Component debemos ir a la sección Build Phases del target ItunesSimpleSearchUITests y hacer lo siguiente:

  • Haz clic en el botón (+) y selecciona New Copy Files Phase.
  • Selecciona Absolute Path para Destination .
  • En la sección Path agrega:
$(TARGET_BUILD_DIR)/../../ItunesSimpleSearch.app/Frameworks
  • Verifica que Copy only when installing no esté seleccionado.
  • Haz clic en el botón (+) que se encuentra abajo y agrega el elemento AppFramework.framework.
  • Verifica que Code Sign On Copy esté seleccionado.

Si sigues todos estos pasos, debería verse así:

Agregando AppFramework — haciendo la magia posible

Finalmente, si intentas correr todas las pruebas podrás ver que éstas correrán sin problemas. ¿Estamos listos?… Aun no. Tenemos un paso más que hacer, debido a que nuestro proyecto está escrito en Swift.

Agregando soporte para Swift

Para poder escribir nuestros test en Swift debemos ir a la sección Build Phases del target ItunesSimpleSearchUITests y hacer lo siguiente:

  • Crear el archivo ItunesSimpleSearch-Bridging-Header.h en el target de UI Tests y agregar los siguientes imports:
#import "AppFramework/Action/GREYAction.h"
#import "AppFramework/Action/GREYActionBlock.h"
#import "AppFramework/Action/GREYActions.h"
#import "CommonLib/DistantObject/GREYHostApplicationDistantObject.h"
#import "CommonLib/Matcher/GREYElementMatcherBlock.h"
#import "CommonLib/Matcher/GREYMatcher.h"
#import "TestLib/AlertHandling/XCTestCase+GREYSystemAlertHandler.h"
#import "TestLib/EarlGreyImpl/EarlGrey.h"
  • Agregar en Objective-C Bridging Header :
$(SRCROOT)/ItunesSimpleSearchUITests/ItunesSimpleSearch-Bridging-Header.h
  • Verificar que en Runpath Search Paths esté la entrada @loader_path/Frameworks , ya que esto permite la ejecución en dispositivos físicos.
  • Descargar el archivo EarlGrey.swift y agregarlo a nuestro target de pruebas UI.

Llegado este punto, AL FIN podemos comenzar a escribir nuestras pruebas de caja negra. Sin embargo, esto lo abordaré en la parte dos. El resultado de todo lo realizado acá lo pueden encontrar en la rama black-box-setup .

¡Estén atentos!

--

--