Estrategia de testing en Frontend
Este artículo se divide en dos secciones. En la primera, nombraré los tipos de tests y explicaré su esencia y propósito. En la segunda, hablaré sobre qué estrategia de testing deberíamos seguir en Frontend, bajo mi punto de vista.
El objetivo del testing
El objetivo del testing es asegurar la calidad y confiabilidad del producto dentro de un entorno determinado. En concreto, se busca:
- Detectar errores lo antes posible: Cuanto antes se identifique un error, más sencillo será corregirlo y menor será su impacto en términos de tiempo y costes.
- Verificar el cumplimiento de las especificaciones: Asegurar que el producto se ajuste a las expectativas del cliente, de producto y de otros interesados.
- Garantizar estabilidad y rendimiento óptimos: El software debe funcionar correctamente y de manera eficiente bajo diversas condiciones.
Al lograr estos objetivos, se mejora la experiencia del usuario y se evitan gastos innecesarios para la empresa, es decir, tiempo y/o dinero.
Tipos de tests
Tests de desarrollo
Los tests de desarrollo son aquellos que se escriben antes o durante el desarrollo de una funcionalidad.
Son una herramienta que nos ayuda a definir el comportamiento esperado de una funcionalidad y a verificar que este se cumpla.
Veámoslos en detalle.
Tests estáticos
Los tests estáticos son aquellos que se ejecutan sin necesidad de correr el código.
Estos tests son los primeros que nos dan información sobre posibles errores y problemas de calidad. Por ello, es fundamental
tener una buena configuración en el proyecto para que se ejecuten de manera automática.
En el entorno Frontend, los tests estáticos más habituales son:
- Linters: Herramientas que analizan el código para detectar errores y evitar malas prácticas.
- Type checkers: Sistemas que verifican la coherencia de los tipos, ayudando a prevenir errores de integración y compatibilidad.
- Code formatters: Herramientas que dan un formato consistente al código, facilitando su lectura y mantenimiento.
Tests unitarios
Los tests unitarios se centran en verificar el comportamiento de unidades individuales de código de forma aislada.
En Frontend, una unidad puede ser:
- Una función. Ej.: una función que formatea una fecha.
- Un componente UI básico. Ej.: botón, acordeón, select, etc.
- Un hook reusable. Ej.:
useClickOutside
,useDebounce
, etc.
Características principales:
- Aislamiento: Se prueba cada unidad de forma independiente, mockeando las dependencias externas.
- Mantenibilidad: Ayudan a detectar regresiones cuando se modifica el código.
- Documentación: Sirven como ejemplo de uso y documentación del código.
- Velocidad: Son rápidos de ejecutar debido a su naturaleza aislada.
Tests de integración
Los tests de integración verifican que diferentes partes de la aplicación (componentes, hooks, funciones, etc.) funcionan correctamente juntas.
A diferencia de los tests unitarios, estos validan la interacción entre múltiples piezas de código.
Características principales:
- Alcance más amplio: Prueban múltiples unidades trabajando en conjunto.
- Casos de uso reales: Simulan escenarios más cercanos al uso real de la aplicación.
- Menos mocks: Solo se mockean dependencias externas (APIs, servicios, etc.).
- Mayor confianza: Detectan problemas que los tests unitarios no pueden encontrar.
Tests end-to-end (E2E)
Los tests end-to-end (E2E) simulan el comportamiento real de un usuario interactuando con la aplicación en un entorno lo más cercano posible a producción.
Estos tests son los más completos pero también los más costosos de mantener.
Características principales:
- Entorno real: Se ejecutan en un navegador real, interactuando con la aplicación completa.
- Flujos completos: Prueban funcionalidades de principio a fin.
- Sin mocks: Se utilizan los servicios y APIs reales del entorno. Si usas mocks, no estás haciendo tests E2E.
- Mayor cobertura: Validan la integración de todos los componentes del sistema.
Monitorización y alertas
La monitorización y las alertas son una parte crucial de nuestra estrategia de testing que ocurre en producción.
Nos permiten detectar problemas reales que afectan a nuestros usuarios y actuar de forma proactiva.
Algunas métricas clave a monitorizar son:
- Rendimiento o Web Performance: Revisa las métricas web esenciales.
- Errores y excepciones: Errores no capturados, fallos en peticiones HTTP o bloqueos de la aplicación.
- Uso y comportamiento: Conversión de los flujos principales, tiempo en página, tasa de rebote, dispositivos y navegadores utilizados, etc.
Es importante conocer cuándo alguna de las métricas tiene una variación significativa o muestra anomalías. Esto lo sabremos gracias a las alertas.
Una buena base y configuración de alertas nos ayudará a detectar problemas que los tests automatizados no pueden prever, ofreciendo datos reales de
uso y ayudándonos a priorizar las acciones necesarias para su corrección. Además, nos ayudarán a medir el impacto de los cambios que realizamos.
No voy a recomendar ninguna herramienta específica para monitorización y/o alertas. Mi opinión se basa en utilizar herramientas concretas
para usos concretos, evitando así la típica herramienta que hace de todo, pero solo una cosa bien.
Tests manuales
Los tests manuales son aquellos que se realizan directamente sobre la aplicación, y complementan a los tests automatizados.
A pesar de los esfuerzos en la automatización, los tests manuales siguen siendo una parte imprescindible de la estrategia de testing.
Pero... ¿Por qué son necesarios?
- Validación de UX: Permiten evaluar aspectos subjetivos como la usabilidad y la experiencia de usuario.
- Casos edge: Ayudan a descubrir escenarios que no se contemplaron durante el desarrollo.
- Validación de requisitos: Permiten verificar que el producto cumple con las expectativas del negocio.
¿Y cuándo son más valiosos?
- Durante el desarrollo de nuevas funcionalidades. Sí, esto también son tests manuales.
- Cuando la automatización es muy compleja o costosa.
- Cuando es necesario evaluar aspectos subjetivos.
- Para investigar bugs reportados por usuarios.
Es importante encontrar un balance entre tests automatizados y manuales. No todo debe o puede ser automatizado,
pero tampoco debemos depender exclusivamente de tests manuales.
Estrategia de testing en Frontend
Una vez explicadas las diferentes tipologías de tests y comprobaciones, queda matizar cómo se distribuyen. Es decir,
qué cobertura debe tener cada tipo de test, y qué coste tienen en relación al coste de desarrollo, ejecución y/o económico.
Tipo | Cobertura | Coste |
---|---|---|
Tests estáticos | Total | Bajo |
Tests unitarios | Baja | Bajo |
Tests de integración | Muy alta | Medio |
Tests E2E | Muy baja | Alto |
Monitorización | Total | Medio |
Alertas | Media | Medio |
Tests manuales | Alta | Muy Alto |
La tabla anterior es una aproximación y puede variar en función de las necesidades y características de cada proyecto, pero sirve como base para definir una estrategia de testing efectiva.
Teniendo esto en cuenta, mi recomendación es la siguiente:
- Tests estáticos: aplican a la totalidad del código y el proyecto tiene una buena configuración para integrarse con el editor de código.
- Tests unitarios: cubren todos los casos de uso en componentes de UI básicos, hooks y funciones.
- Tests de integración: cubren todos los casos de uso en componentes de UI compuestos, es decir, que integran múltiples piezas. Cada test testeará únicamente los casos de usos propios de dicha integración y delegará el funcionamiento de las piezas integradas a sus tests unitarios o de integración.
- Tests E2E: únicamente cubrirán los flujos más críticos del negocio. Solo tendremos E2E cuando tengamos una buena base de unitarios e integración.
- Monitorización: guardaremos trazas, generadas por el uso de los usuarios, de las métricas más importantes, es decir, errores, performance, uso, etc. Además, podemos crear monitores que evalúen en un entorno aislado el rendimiento de la aplicación para detectar problemas antes de que los usuarios los experimenten.
- Alertas: cubrirán los casos de uso más importantes y los aspectos que más impacto tengan en las métricas más críticas.
- Tests manuales: además de probar que el desarrollo funciona en nuestro entorno local, debemos revisar que en producción también.
Con todo esto, y a modo resumen, esta estrategia te hará tener un 100% de cobertura en tests estáticos, una enorme cobertura de tests de integración, algunos tests unitarios, pocos tests E2E y una buena monitorización y alertas. Además, todos los desarrolladores serán conscientes de probar con sus manitas las cosas que tocan.
Seguramente te encontrarás con algún proyecto antiguo que no tiene o tiene pocos tests. En ese caso, mi recomendación es que empieces configurando los tests estáticos y dediques esfuerzos en añadir tests de integración. Una vez tengas una buena base de tests de integración, será más sencillo añadir tests unitarios y de ser necesario, E2E.