Potencia tu Unit Testing en Flutter: ¡Utilidades para ahorrar tiempo y escribir tests más rápido y simple!

Carlos Daniel
3 min readJul 24, 2023
Photo by Yuriy Vertikov on Unsplash

Sin entrar a detallar la infinidad de conceptos en unit testing en software development, que están disponibles en muchísimas referencias bibliográficas, pasaré esta vez a compartirles una serie de utilidades que solemos usar en nuestro equipo de trabajo y que nos han ayudado a ahorrar un montón de tiempo mientras escribimos nuestras pruebas unitaras.

Extensiones de Mockito

Para los unit tests, usamos Mockito (que se basa en el framework Mockito de Java) como librería para mockear los objetos que hace parte de nuestra lógica de negocio. Y según nuestro contexto de negocio, hacemos uso de las extensiones de Dart para facilitar y flexibilizar la escritura de nuestras pruebas. Así, si queremos probar y mockear un flujo de éxito (Success), o un Futuro, o una respuesta a un Stream en orden, o una falla (Failure).

Por ejemplo, para mockear un response de Success y/o un Stream, lo hacemos de la siguiente manera (lo cual nos evita para cada when tener escribir siempre los post execution del answer):

when(pushNotifier.requestPermissions()).thenAnswer((realInvocation) => <<something to match>>);
when(pushNotifier.onTokenRefresh()).thenAnswer((realInvocation) => <<Some stream>>);

Y solo llamamos a la extensión (thenSucceed thenStream)

Builders y Mother Objects

Es una mezcla extraña la que usamos, pero creo que sacamos lo mejor de ambos mundos en nuestro beneficio. Esto es, creamos test data general de nuestros objetos para facilitar los escenarios de testing, a través del patrón Builder y los Mother Objects. Así, solemos separar por contexto nuestros objetos de testing en objetos para (no son los únicos, pueden haber más como de data base, por ejemplo):

  • API (los asociados a la capa de llamado de red — endpoints).
  • HTTP (los objetos response http, o failure con un error code o un null response).
  • Modelo (los objetos propios de nuestro modelo de negocio).
  • Librerías (los objetos sobre los cuales no tenemos control por ser de libs externas, pero que podemos usar dentro de nuestra app)

Por tanto, algunos ejemplos serían (no les compartiremos todos, solo algunos mezclados que sirven como referencia, ya cada quien en sus proyectos los acomoda y refina a su necesidad):

Stubs

Sabemos que dentro el mundo de unit testing existen varios términos para referirse a pedacitos de funcionalidades y o respuestas/resultados ante ciertos eventos, y los Stubs son uno de ellos. Y no entraremos a detallar cada referencia, solo les compartimos este artículo interesante escrito por Martin Fowler que ayuda a aterrizar algunos de estos conceptos (este artículo no es la palabra definitiva, pero plantea de una forma simple diferencias a tener en cuenta)

Para nuestro equipo, el uso de Stubs ha sido de mucha utilidad en nuestros unit tests cuando por ejemplo, debemos tener pequeños objetos pre-cargados en memoria que nos ayuden a definir el entorno de una prueba. Esto es, tenemos pro ejemplo un objeto Storage que encapsula un pequeño set de datos en memoria a través de SharedPreferences. Dicho objeto Storage por inversión de dependencias, hace parte del constructor de otros objetos, como por ejemplo SessionStorage. Si nosotros quisiéramos testear una lógica de negocio que incluye al SessionStorage entonces creamos un Stub del Storage y a este objeto le seteamos los datos necesarios para que las pruebas puedan abarcar los diferentes escenarios:

Y así lo usamos:

Ahora, hoy vamos hasta aquí, pero creemos que con estas 3 utilidades cubrimos un montón de escenarios de nuestros unit tests de forma simple, legible y fácil de escribir e implementar.

Probablemente, tengamos en el futuro algunos detalles adicionales y otras buenas prácticas para compartir en este súper mundo de las pruebas unitarias, que han sido un gran beneficio para nuestro equipo de trabajo y posiblemente lo sean para ustedes también.

Agradecimientos a Daniel Gómez y a Julián Sotelo, de mi equipo de trabajo, también autores materiales e intelectuales de estas prácticas

--

--

Carlos Daniel

Android & Flutter Developer. GDE for Android & Mobile Engineer.