Pruebas de extremo a extremo e integración

Pruebas end-to-end y de integración

Hace un tiempo estaba discutiendo con unos compañeros de trabajo con respecto a si un conjunto de pruebas end-to-end probaban lo mismo que un conjunto de pruebas de integración, no pudimos llegar a un acuerdo mutuo al final de la discusión, recuerdo haber mencionado investigar al respecto y plasmarlo en algún lado.

Luego de investigar a fondo ambos términos pienso que en aquel momento estábamos discutiendo con una base errónea (tal vez por eso no llegamos a ninguna conclusión clara), básicamente las pruebas end-to-end no se pueden comparar con pruebas de integración porque en realidad la primera es un tipo de la segunda.

Googleando un poco acerca del tópico me encontré con este mismo error, muchas personas escriben acerca de pruebas end-to-end e intercambiaban este término con pruebas de integración implicando que son sinónimos.

Ya sabemos que las pruebas end-to-end son un tipo de pruebas de integración, entonces una duda sale a flote, ¿con qué estábamos comparando las pruebas end-to-end cuando decíamos que estas prueban lo mismo que una prueba de integración? La respuesta es sencilla, pruebas de sistema.

Perfecto, ahora si tenemos algo que comparar, pruebas end-to-end contra pruebas de sistemas. Ambas son pruebas de integración, lo único que cambia es el contexto de dichas pruebas, prueban lo mismo (con algunas variantes) desde diferentes lugares y de diferentes maneras. Las pruebas end-to-end prueban tanto la funcionalidad del sistema como el flujo de pantallas del mismo, para este artículo nos enfocaremos en las pruebas end-to-end en la WEB (por eso menciono flujo de pantallas). Sin embargo este término funciona para el contexto móvil, desktop o cualquier cosa que sea la interfaz de comunicación de un sistema. Las pruebas de sistemas son las realizadas en el contexto de servidor (backend), prueban la funcionalidad del sistema igualmente pero también la interoperabilidad entre componentes y sus dependencias (estas pruebas son directamente desde el código y no a través de una interfaz de comunicación).

¿Cuáles de estas 2 deberíamos usar? (si tuviéramos la oportunidad de elegir solo una), esto depende netamente de la naturaleza del proyecto, trataré de listar algunos beneficios y contras de cada una y aportaré mi opinión al respecto, sin embargo recordando siempre que una de las razones de más peso es la naturaleza del proyecto.

Empecemos por las pruebas end-to-end:

Pros:
Además de probar el correcto funcionamiento del sistema, pruebas también el flujo de pantallas.
Implícitamente se prueban cosas muy internas del sistema a través de sus resultados, por ejemplo que el sistema de notificaciones push esté funcionando correctamente, o que el proceso de login y logout tengan el comportamiento esperado.
Prueba directamente con lo que el usuario final (o consumidor) interactúa.
Se pueden lanzar en diferentes navegadores, asegurando que todo funciona sin importar cuál sea (esto ha mejorado mucho con el tiempo, anteriormente el uso de hacks para hacer que algo funcione correctamente en cierto navegador en específico era el caso común).
Mientras más casos de pruebas se tenga más fácil es crear nuevos casos (esto claro si se sigue bien el patrón PageObject y se mantiene el código de pruebas en buen estado con buenas prácticas).

Contras:
Toman mucho tiempo en correr, normalmente tendremos que correrlos separados para ahorrar tiempo, por ejemplo, si se está haciendo un cambio en el login solo correr los casos de pruebas de login.
No son 100% consistentes, a pesar de que se ha avanzado bastante con el tema de los navegadores, a veces se pueden obtener comportamientos extraños que hacen que los test se rompan pero al correrlos nuevamente el mismo caso puede pasar satisfactoriamente.
Si el diseño o cara del proyecto cambia es altamente probable que se tengan que desechar las pruebas, ya que están altamente emparejados con el HTML & CSS, es posible lograr mantenerlos pero esto depende de una gran organización tanto en el código HTML/CSS como en la correcta abstracción del uso de los mismo en las pruebas.
Si se tiene un flujo de Integración continua y Despliegue continuo, la inconsistencia de los test se convierte en un problema, ya que a veces pueden fallar sin razón aparente retrasando así un proceso de despliegue.
Es difícil borrar los datos creados desde estas pruebas, pues la API que tenemos, que es básicamente lo que el usuario puede ver/usar (con algunos accesos especiales al código JavaScript), normalmente no nos permite borrar cosas a la ligera. Por lo tanto tenemos que recurrir a hacks o artilugios para lograr esto.

Ahora vamos con las listas para Pruebas de Sistema:

Pros:
Se puede probar la lógica de negocio sin intermediarios o interferencias.
Son bastante rápidos, así que pueden ser corridos múltiples veces sin problemas. En sistemas complejos pueden tomar algo de tiempo y dependiendo específicamente de qué se está probando, sin embargo siempre serán más rápidos que las pruebas end-to-end, sin duda.
Eliminar los datos que las pruebas generan es muy fácil, incluso se puede simplemente crear una base de datos nueva para realizar estas pruebas (como parte del proceso de pruebas) y al concluir las pruebas eliminar la misma.
Normalmente son más rápidos de implementar que las pruebas end-to-end (sin embargo hay que tomar en cuenta que la velocidad de implementación de las pruebas end-to-end aumenta conforme más tengamos), esto es bastante dependiente de lo que se está probando.
La única forma de que estas pruebas queden obsoletas es que la lógica de negocio cambie por completo, cosa que probablemente nos haría comenzar un nuevo proyecto en vez de hacer cambios en el que tiene las pruebas actuales (¿A alguien le ha ocurrido esto en la vida real? A mi no, lo dudo).

Cons:
Si tienes pruebas unitarias es difícil decidir por esta opción, ya que se puede sentir como que es demasiado (personalmente, nunca es demasiado), sin embargo es algo común que pasa.
Hay que ser cuidadoso al momento de crear las pruebas no creando dependencias con frameworks o cosas asi, los mismo deberían ser agnósticos de la tecnología (por razones obvias, deben estar en el mismo lenguaje del proyecto).
A veces son difíciles de empezar a crear si ya el proyecto está comenzado, ya que en muchos casos el mismo no está diseñado con las pruebas en mente (esto es más un problema de arquitectura de proyecto, sin embargo no es un problema que ocurre con las pruebas end-to-end).
En el contexto de servidor, es común que se prefieran las pruebas unitarias sobre las pruebas de sistema, suponiendo el caso de que se tiene el presupuesto para solo una.

Conclusión

Por último mi opinión con respecto a cuál elegiría de estos dos tipos de pruebas, tendría más inclinación por las pruebas de sistema, la razón es sencilla, normalmente la parte crítica de una aplicación se encuentra en el servidor (la lógica de negocio). Sin embargo repito por tercera vez que lo más importante a tomar en cuenta es la naturaleza del proyecto, un ejemplo donde elegiría end-to-end sobre pruebas de sistema es un juego móvil. el mismo solo guarda en el servidor los usuarios y su puntaje, en este caso es mucho más importante la experiencia del usuario en el juego que la lógica sencilla detrás del puntaje y los usuarios, excepcionalmente preferiría encontrar maneras de probar la interfaz del juego más que probar la lógica trivial en el servidor.

Si pudiera devolver el tiempo atrás y tener la discusión que hizo posible éste artículo lo primero que haría es cambiar la base errónea que habíamos tomado con respecto a la comparación y estoy 100% seguro que habríamos llegado a un acuerdo inmediato sin problemas.



Article by: Joseph Arrieta at Bixlabs, Uruguay