Estrategia de Contract Testing: Producer driven o Consumer driven
En un post anterior hemos visto cómo surgen nuevas necesidades en el ámbito del testing derivadas de la evolución de las arquitecturas de las aplicaciones. En él, hablamos de cómo con el paso de los años hemos pasado de desarrollar aplicaciones basadas en una arquitectura monolítica a aplicaciones basadas en (micro)servicios. Donde antes teníamos tests centralizados en una única aplicación, ahora pasamos a tenerlos divididos en varias, de forma que tendremos testeadas cada una de ellas de forma independiente y estanca.
Hemos presentado un ejemplo sencillo de una aplicación, que nos ha servido para establecer algunos conceptos (como consumer, producer, servicio) y que nos ha permitido poner en evidencia una nueva necesidad: tan importante como testear las funcionalidades en consumer y producer de forma independiente lo es asegurar que la interacción entre ambos es correcta. Esta necesidad podemos abordarla mediante test end-to-end, pero si bien estos tests ya resultan complejos de implementar/ejecutar en aplicaciones monolíticas en aquellas que no los son la complejidad es mayor.
En este punto surge una idea: podría ser suficiente con verificar entre consumer y producer que existe un acuerdo que ambos cumplen. Aquí es donde descubrimos un nuevo concepto: Contract Testing.
Y ¿qué es Contract Testing? En la documentación de Pact encontramos la siguiente definición
Es una técnica que nos permite probar la integración de varias aplicaciones, verificando en cada una de ellas que los mensajes que envía o recibe (dependiendo de su rol consumer/producer) se ajustan a un acuerdo que está documentado en un contrato.
Este concepto podríamos desgranarlo y traducirlo (a nivel práctico) en los siguientes puntos:
- Existirá un acuerdo concreto definido al que tanto consumer como producer tendrán acceso.
- En el consumer, tendremos tests donde las peticiones se harán a un “stub” del producer que cumplirá el acuerdo definido.
- En el producer, tendremos tests donde se realizarán peticiones basadas en el acuerdo definido.
Dependiendo de la herramienta/framework que tomemos como referencia, el concepto de “acuerdo entre consumer y producer” recibe el nombre de pacto o contrato. Pero no dejan de ser diferentes nombres para el mismo concepto: una especificación de cómo deben ser las llamadas y respuestas para consumir los servicios ofertados por el producer.
Volviendo al mismo ejemplo que hemos utilizado en el post anterior esta idea podríamos representarla como sigue:
Una vez presentado el concepto detrás de Contract Testing en términos generales, vamos a profundizar un poco más viendo los enfoques y herramientas existentes.
Enfoques
En la literatura principalmente encontramos la relación Contract Testing → Consumer Driven Contract Testing. Esto al principio hizo que me resultase más difícil comprender el concepto subyacente. Tras leer varios post, documentación…. llegué a la conclusión de que el motivo de esta asociación parte de la idea de que un servicio de un producer carece de sentido si no hay alguna aplicación utilizándolo (consumer). Por tanto, parece lógico que quien establezca qué acuerdo debe cumplirse sea el consumer, mientras que en el producer debería recaer la responsabilidad de satisfacer las necesidades fijadas por consumer (de ahí la coletilla de “Consumer Driven”).
Vale, bien, pero en los proyectos que he conocido de cerca, la casuística no ha sido precisamente esa. El escenario ha sido el de un producer transversal a varias aplicaciones, que no conoce a sus consumers, y a quienes les oferta unos servicios determinados.
Así que, no me terminaba de encajar. Tuve que dar un paso atrás y verlo en perspectiva para llegar a entender que, en realidad, podríamos encontrarnos con dos situaciones en función del proyecto que tuviésemos entre manos (diferentes en forma pero iguales en concepto) y así dependiendo de quién sea el que define el acuerdo podríamos tener dos enfoques:
- Consumer Driven Contract Testing
- Producer Driven Contract Testing
¿Por qué no? El nombre no deja lugar a dudas: en un caso la definición del contrato nace en el consumer y en el otro del producer. La verdad es que hubo un momento en que Producer Driven Contract Testing parecía que fuese invención mía (no hay más que ver la búsqueda en Google de este término o de provider-driven…), pero encontré una referencia a ese término (como veremos un poquito más adelante) lo cual me dió pie a continuar con mi esquema mental.
El concepto base, en ambos casos, no deja de ser el mismo. Sin embargo dependiendo del enfoque que encaje mejor con nuestro proyecto podremos decantarnos por uno u otro. Lo mismo sucede a la hora de elegir las herramientas para hacerlo: dependiendo de nuestras necesidades podremos elegir entra las diferentes herramientas existentes.
Herramientas
Basándonos en el ejemplo presentado al inicio (y sabiendo que es un proyecto Spring Boot gestionado con Maven), las herramientas más populares que hemos encontrado que podríamos utilizar en nuestro proyecto son:
-
Pact
Esta herramienta está fuertemente acoplada con Consumer Driven Contract Testing, básicamente porque los pactos estarán siempre en la parte consumer. En la documentación podemos leer:
Pact is a code-first consumer-driven contract testing tool, …. The contract is generated during the execution of the automated consumer tests
-
Spring Cloud Contract
Aunque en su descripción dice:
Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. Currently Spring Cloud Contract consists of the Spring Cloud Contract Verifier project.
Puede utilizarse tanto en un sentido como en otro. De hecho, en la documentación Pact indican que Spring Cloud Contract nació con el enfoque provider-driven.
Pact has always been a consumer-driven contract testing framework whereas Spring Cloud Contract started as provider-driven.
¡Parece que no me he inventado el término!, tampoco estaré tan desencaminada ¿no?
Hasta aquí el proceso que seguí hasta llegar a comprender que detrás Contract Testing hay más de un enfoque y múltiples herramientas. Como siempre, dependerá del proyecto que tengamos entre manos para elegir lo que más nos encaje.
Mucha chapa y poco código, ¿verdad? Yo soy de las que para aprender/entender realmente algo tengo que ponerlo en práctica…. así que si te pasa lo mismo que a mí, no te preocupes, aquí no terminamos: en breve publicaré un pequeño ejemplo utilizando Spring Cloud Contract.