Screenshots para tus tests

Mauricio Chirino
PeYa Tech
Published in
6 min readApr 15, 2021
Múltiples UI para PedidosYa

Probablemente te haya pasado: pasaste horas (incluso días) maquetando esta UI impecable, esa que construiste mano a mano con el equipo de diseño y estás satisfecho con el resultado. Ahí está, una interfaz limpia, responsiva, con los colores y las proporciones deseadas hecha realidad por tu código.

Si bien nada en código es rígido o está escrito en piedra (de ahí el prefijo soft) la experiencia te enseña que debes dejar alguna salvaguarda para tu UI, especialmente cuando trabajas en un equipo grande con un design system en constante evolución; es muy fácil para un colega (o incluso para nosotros mismos en el futuro) cambiar algún color/fuente de la librería de UI compartir y estropear algo de alguien más*. Ten todo esto en mente mientras debes sacar tiempo para armar los tests, navegar hasta la pantalla que estás integrando, setearla en el estado específico que necesitas en este escenario y volver a repetir todo esto con cada estado a fin de tener certeza que tu solución está funcionando para cada permutación posible…

Compiling de xkcd

Tiene que haber una mejor manera 🤔 (no tendría sentido hacerte leer hasta acá si no la hubiese después de todo)

Te presento el screenshot testing

Si bien Apple da soporte nativo para objetos lógicos, desde el principio del desarrollo iOS existió un gap para el coverage de testing relacionados con los objetos visuales. El concepto es sencillo: hacer tests unitarios entorno a elementos de UI por código, es decir, generar una representación gráfica (un .png) de nuestras vistas y compararla con una imagen de referencia para verificar.

¿Cómo hacemos en PedidosYa para no volvernos locos cuando debemos elaborar un nuevo feature? Un pequeño “truco” son las pruebas de snapshot mencionadas anteriormente. Hay varios sabores de éstas, conozco colegas que no les gusta incluir librerías de terceros y arman sus propios mecanismos:

Configuración de Snapshot para iPhone 8 por Gustavo Londoño 🇨🇴

Hace ya algunos años Facebook liberó el pod de su librería interna que cumplía este mismo propósito (hoy día mantenida por el equipo de desarrollo de Uber en otro repo). Sin embargo el enfoque de este artículo es en otra librería más reciente, hecha totalmente en Swift a diferencia de sus predecesoras: snapshot testing. Seamos pragmáticos y hagamos uso de ella, después de todo cuenta con buen soporte de la comunidad y está muy bien documentada.

Al final del día debe existir un balance entre forzar estándares y dejar espacio para la creatividad e innovación, bien sea que hagas tus pruebas desde 0 o te apoyes en librería de terceros, lo realmente importante es que las tengas.

¡Mucho ruido y pocas nueces Mauri!

Supongamos que un caso puntual que tuvimos en algún momento en la app: formateo de Labels. Debíamos generar Labels con íconos al principio, al final y tachado (con colores custom). Bastantes estados para poner un Label con múltiples buildeos en el interin para probar que en efecto luzca como quieres la UI así que es un caso ideal para probar nuestro enfoque de snapshots.

Una vez que tengamos la librería agregada a nuestro proyecto, escribimos nuestra prueba con el texto tachado

applyStriketroughFormat es un método customizado para configurar texto tachado así como el tipo de fuente que mostrará

La primera vez que corremos la prueba mostrada arriba arroja un error al no encontrar una imagen de referencia con la cual hacer la comparación, esto a su vez genera una imagen referencia. La siguiente vez que corremos la prueba obtenemos nuestro esperado diamante verte ✅

Imagen de referencia generado por el snapshot escrito en el snipet de código de arriba

Snapshot testing no sólo te permite hacer pruebas de componentes individuales, incluso nos deja hacer capturas de ViewControllers enteros. Supongamos que en una vista demo tenemos todas las variaciones de nuestro Label formateable:

Vista demo con algunas de las permutaciones posibles de nuestro Label formateable
Es recomendable especificar el tipo de dispositivo contra el cual hacer la comparación en casos de ViewControllers enteros.

Para citar un ejemplo en concreto, algún tiempo atrás tuve que hacer una migración de código algo delicada para el formulario de búsqueda de direcciones. Suena como algo sin importancia pero en situaciones cuando alguno de nuestros usuarios no tiene su GPS activo y se encuentra en un lugar fuera de alguna de sus direcciones almacenadas (o directamente está deslogueado), dicho formulario se convierte en el punto de entrada a la app. Sin dirección, no hay delivery después de todo.

Pueden ser varias las permutaciones de dicha pantalla, por lo cual esta tarea era ideal para aplicar snapshot testing y agilizar la salida sin sacrificar calidad o introducir regresiones.

Algunas de las permutaciones de dicha pantalla, son 8 en total

Notas finales

Debemos tener cuidado por ejemplo en las siguientes situaciones:

  • Algún ViewController/componente de UI está cubierto por la snapshots ve alterado y/o agregado algún comportamiento y dicha alteración no está a su vez cubierta por prueba(s) unitaria(s). Esto generará falsos positivos y falsa confianza en nuestros deploys, pese a seguir contando con el diamante verde de nuestra suite de tests.
  • El coverage por sí solo no es una medida confiable para la calidad ni cobertura de nuestro code base, de no tener claro esto los snapshots nos van a arrojar coverage sumamente altos en caso de testear ViewControllers
  • No recomiendo usar snapshots en UI que esté en estado de rediseño frecuente (varias iteraciones al día por dar cifra). Suena exagerado el número pero durante un rediseño de design system, es mejor desistir de ellos hasta lograr una versión estable y posteriormente dejar el snapshots con estados válidos.

Habiendo dejado en claro los aspectos no tan favorables, terminemos resumiendo el lado positivo de este enfoque:

  • Es muy económico (rápido) probar y validar estados de UI. Para quienes hemos luchado con las pruebas de UI nativas que provee Xcode, conocemos lo lentas que pueden ser. Todo test lento eventualmente dejará de correrse y un test no corrido es igual a un test no escrito -no sirve de nada-
  • Deja cierta garantía automatizada que cualquier cambio de UI es intencionado, de lo contrario fallarán las validaciones al comparar con las snapshots guardadas.

No existe silver bullet en esto de la programación así que tampoco debemos abusar de las snapshots, entender que es un herramienta más en nuestro arsenal diario de desarrollo y usarlas con criterio.

*: en PedidosYa implementamos buenas prácticas de integración continua, un ejemplo de ello es que código no puede ser mergeado a producción sin pasar por Code Review, sin embargo buscamos optimizar constantemente estos procesos manuales (enriqueciendo nuestra suite de tests y elaborando scripts para no olvidarnos de tediosos pasos repetitivos). Mientras más cosas se automatizan, mayor tiempo conseguimos para enfocarnos en trabajo creativo y desafiante.

--

--

Mauricio Chirino
PeYa Tech

Sr. mobile engineer and fitness rookie. I do what I love and love what I do (thanks God people pay me for it)