Tests.

DIFERENCIA ENTRE TESTS E2E, INTEGRACIÓN Y UNITARIOS.

Siempre te preguntaste como podrías diferenciar qué test hacer y en qué circunstancia, pues aquí la respuesta.
Leer más

e2e

Los tests funcionales o end-to-end, son aquellos que no conllevan un input o entrada determinada, simplemente interactuar con el sistema como si lo hiciera el usuario, dejando a este crear todos los datos, al mismo tiempo que validando que el resultado es el esperado.

Los tests e2e no deben depender de un UI especifico, da igual si el botón esta abajo, arriba, es redondo o cuadrado, o dice enviar, cerrar, etc… los e2e tests deberían funcionar independientemente de esto, por ello la importancia del uso de atributos específicos en los elementos HTML necesarios.

El objetivo de los tests e2e, no es verificar los datos en pantalla, sino verificar que un elemento existe en esta, básicamente, lo que se espera que vea el usuario luego de realizar una acción.

Siguiendo estas guías básicas nos aseguramos de hacer tests útiles y acordes a la circunstancia que estamos deseando cubrir.

En resumen, los tests e2e no reciben un input o entrada determinada y tampoco verifican una salida de datos especifica.

Integración

Los tests de integración, son aquellos que tienen multiples inputs o entradas determinadas y esperan un resultado en concreto. Con esta simple afirmación podemos aplicar los tests a componentes frontend o API endpoints.

Los tests de integración son aquellos que agrupan una serie de unidades, ya sean componentes, clases, métodos, etc.

El objetivo de los tests de integración es verificar un resultado concreto de una entrada multiple de datos concreta, haciendo énfasis en la palabra “concreto”, ya que es el pilar de estos tests. Una entrada o input de datos explícitos por una salida o output de datos específica.

Unitarios

Los tests unitarios son los más sencillos ya que solo conllevan una entrada o input por una salida o output. Cualquier código que no cumpla con esta condición no podría recibir un test unitario.

Tanto componentes frontend como API endpoints pueden recibir test unitarios mientras que sus parámetros de entrada o input sean zero (0) o uno (1) y su salida o output sea una (1).

El objetivo de estos tests es verificar la inmutabilidad de la funcionalidad del código en independencia de su implementación.

¿Cuándo hacer los tests de cada tipo?

Toda aplicación que sea de uso público debe tener tests asociados, de lo contrario estaríamos frente de un prototipo o MVP. Con estas simples afirmaciones podemos identificar qué tests hacer, cuándo y para qué circunstancias.

Un proyecto de uso público debe tener al menos, tests de e2e para verificar que el desarrollo del mismo no interfiere con la experiencia de usuario negativamente.

Un proyecto de uso público comenzará a recibir tests de integración para resolver incidencias reportadas por el uso del mismo que requieran de una entrada especifica de datos con tal de reproducirlos y así poder corregirlos.

Un proyecto de uso público debe recibir tests unitarios como consecuencia de la escritura de tests de integración.

¿Debe mi proyecto tener tests desde el principio?

No.

Lo más probable es que tu proyecto comience como un start up, con una idea sin mucha forma. Por lo que al principio se espera que se escriba un MVP o prototipo de lo que será. En esta etapa del proyecto escribir tests impactaría en al tiempo para llegar al mercado y tendría un costo de oportunidad alto, además de que potencialmente la aplicación cambie su lógica, estructura, flujo, etc. Los tests solo entorpecerían la creación del MVP (producto mínimo viable).

Los tests, son requeridos cuando el proyecto se determine como listo para uso público y su funcionalidad, aunque no acabada, este ya determinada.

¿Qué hay de los tests regression, smoke y otros?

Cuando los tests comienzan a crecer, estos se comienzan a segregar en subgrupos dentro de cada tipo, para así facilitar su ejecución y agilizar el desarrollo y los procesos de CI (integración continua).

Esta subdivision de tests es arbitraria, por lo tanto, no recomendable.

Los tests se deben subdividir en base a las funcionalidades afectadas por el código nuevo y estos deben ser escogidos por el desarrollador. Esto agiliza el desarrollo y mejora el conocimiento del conjunto de tests del desarrollador.

¿Cuándo correr los tests y qué tests?

Durante el desarrollo se deben correr aquellos tests de cada tipo que el desarrollador crea oportunos por su impacto en el código escrito.

Todos los tests han de correrse sobre la nueva version previo a su lanzamiento de uso público.

¿Cuándo los tests son malos, inútiles o innecesarios?

Cuando entorpecen el desarrollo activo del proyecto.

e2e

Si los e2e tests estan basados en clases, ids, contenido o cualquier elemento modificable del UI, entonces, estos tests sería “malos”. Serían “inútiles” cuando verifican el funcionamiento de un elemento externo o nativo, como por ejemplo, testear que un link carga una nueva página. Y finalmente, serían “innecesarios” cuando estos verifican que el estado inicial del proyecto es el necesario para que corran los tests, ya que esto se asume cierto en cada uno de ellos.

Integración

Si los tests de integración introducen los datos concretos de forma parcial al código a testear o verifican su salida de forma parcial, estos tests serían “malos”. Serían “inútiles” cuando verifican la salida de datos mediante el UI o al testear código en el que la entrada y la salida esten solo modificadas por elementos aislados, para lo cual test unitarios de cada uno de los elementos sería más “útil”. Y finalmente, serían “innecesarios” aquellos tests que no requiran multiple entrada datos pero que su resultado sean multiples valores o simplemente tests que verifiquen la salida de elementos externos como por ejemplo, testear el mismo framework usado por el proyecto.

Unitarios

Los test unitarios nunca sobran, se pueden hacer tantos como valores pueda recibir una función, de hecho, cuanto más aleatorio sean estos datos, más robusto será nuestro código.

Los tests unitarios “malos” suelen ser los que por una falta de entendimiento de estos por parte de los desarrolladores, se hacen sobre elementos que reciben multiples valores. Un ejemplo de esto sería testear un método que haga uso de una clase en su interior sin hacer un mock del resultado de esta para injectar durante el test unitario.

Los “inútiles” son aquellos que cubren una linea de codigo ya cubierta por otro test o que su entrada de datos no difiere de la de otro test.

Y finalmente en la categoría de “innecesarios” estan todos aquellos tests que verifiquen elementos que no pretendan una modificación de datos, como pueden ser componentes de presentación o métodos get/set de clases.

¿Cómo organizar los tests?

Los tests e2e estan principalmente basado en lógica de negocio, teniendo acceso nulo al código que produce el resultado. Además que pueden diferir en tecnología e infraestructura con respecto al proyecto. Por estos motivos, los tests e2e han de ser un proyecto tangencial.

Los tests de integración y unitarios deben formar parte del código del proyecto, ya que dependen de su tecnología, infraestructura y deben tener acceso directo al código objetivo.

¿Qué tamaño tendran los tests?

La relación de tests con respecto al proyecto es de un 70-30. Esto podría traducirse que por cada 3 lineas de código escrita en el proyecto, se requerirán 7 de test.

No es un valor absoluto pero da una noción del esfuerzo requerido para que un proyecto MVP sea transformado en un uno uso público.

¿En que orden debería escribir los tests?

Aunque la lógica de negocio es lo primero, no se pueden escribir tests e2e sobre nada. En las etapas tempranas de un proyecto se espera que este sea desarrollado como un MVP o prototipo y que demuestre las habilidades básicas requeridas. Una vez esto se ha conseguido, existe una base sobre la que comenzar a escribir tests e2e teniendo en cuenta un UI y funcionalidades básicos. De esta misma forma, cuando el MVP se considera listo y su funcionalidad determinada, comienza la etapa de tests de integración y unitarios. Es aquí cuando se elimina o identifica la deuda técnica y cuando se comienza con el refactor del código, ya sea por errores encontrados no identificados durante el desarrollo ágil del MVP o por mejoras necesarias para escribir tests, mejorar performance, etc.

El objetivo principal de un proyecto de uso público es entregar las funcionalidades básicas de forma sólida en su primera versión y para conseguirlo en obigado el uso de tests. Y su subsiguiente objetivo es preservar estas mientras integra nuevas como mejoras.

Entonces ¿Cuándo comienzo con TDD?

El TDD es una técnica de desarrollo muy efectiva y recomendada siempre y cuando existan ciertos pilares que la sustenten. Podemos pensar el TDD como las diferentes prubeas que se hacen a un vehiculo que esta en producción. No se puede saber si un material es bueno para una parte del vehiculo si este no soporta el peso y la torsión exacta de la posición en la que irá, tampoco tendría sentido hacer estos tests sobre una pieza que no haya seguridad si siquiera formará parte del vehículo por las dudas sobre el diseño inicial. Por este y muchos otros motivos, el TDD es solo aplicable a aquello que sea de uso público.

Una vez un proyecto es de uso público, significa que ya nuestro proyecto trabaja con una determinada BD (base de datos) y unos determinados datos. También significa que los usuarios usan nuestro proyecto por algo determinado, aquello que ofrece, por lo que las piezas aunque no permanentes, son definitivas para la primera versión que se expone al público.

Una vez tenemos el primero prototipo, comienzan las pruebas, comenzamos a testear nuestros incrementos pero desde una base.

Los tests e2e son los que determinaran lo que el usuario espera de un proyecto en cuanto a su uso. Y estos tests pueden escribirse antes que el código al ya tener una base sobre la que planificar su implementación.

Los tests de integración y unitarios son aquellos que nos indicaran que nuestras modificaciones no afectan a la funcionalidad básica y el TDD nos ayudará a mejorar lo existente hasta dar con algo robusto.

El TDD se usa para refinar y planificar el futuro de un proyecto, pero es contraproducente para concebirlo.

¿Cómo lidiar con las incidencias?

Las incidencias de un proyecto no apuntan a un código ineficiente, sino a un defecto o falta de tests.

Si queremos un proyecto de uso público sin incidencias, debemos hacer enfasis en los tests.

Esto simplifica el desarrollo, ya que el equipo de desarrolladores reduce sus inputs o entradas, siendo estas cubrir los tests que fallan y suplir las necesidades de los nuevos tests. Siempre que el proyecto sea de uso público.