Volver
Featured image of post Consumer Driven Contract Testing

Consumer Driven Contract Testing

Introducción

Consumer driven contract testing es un tipo de prueba que nos garantiza que un proveedor cumple lo acordado con un consumidor. Por ejemplo, en una API usaríamos este tipo de pruebas para asegurar que el proveedor recibe una petición y devuelve la respuesta esperada.

Cuando dos artefactos se comunican entre sí, típicamente lo suelen hacer mediante un mensaje, el cual tiene un formato determinado. Ese formato hace que el consumidor dependa del productor para poder funcionar correctamente, ya que su código se ajusta a un determinado formato de mensaje. Ese «acuerdo» entre ambas partes es lo que se denomina «contrato». Es entonces gracias a contract testing cuando podemos testear esa integración y asegurarnos que el mensaje que se envía de un artefacto a otro tiene el formato acordado para que la integración entre ambos funcione a la perfección.

Pero más allá de ser una herramienta para testear la integración entre varios artefactos, también lo podemos usar en el contexto de un único artefacto. Véase el caso de asegurar que una API cumple el formato acordado en su documentación, pero en este caso sin hacer el enfoque en un tipo de consumidor concreto.

Hablamos de una herramienta que nos permite testear cualquier tipo de integración de software, pero que ha tenido su auge en los últimos años para HTTP e intercambio de mensajes entre microservicios.

Tipos de contrato

Contrato explícito

Cuando hablamos de un contrato explícito hacemos referencia al hecho de que el consumidor defina durante la ejecucción de sus test un archivo con la estructura del contrato que espera que se cumpla. Es entonces cuando dicho archivo se valida contra el que genera el proveedor, que lo crea de la misma forma, tras haber ejecutado sus propios test.

La clave de este tipo de contrato es que ambas partes hagan los test necesarios para asegurar que se cumple el contrato.

Dado que tanto proveedor como consumidor son de nuestro dominio, cuando queramos cambiar el contrato entre ambos, propagaremos el cambio cambiando el contrato en el proveedor y propagando el cambio en el consumidor para que ambos se equiparen con la nueva versión.

Contrato implícito

El contrato implícito es muy similar al explícito, con la diferencia de que en este caso el proveedor no puede acoplarse al ciclo de test entre consumidor y proveedor. El caso más típico de como puede ocurrir esto es el caso de una API pública. Podemos consumirla, pero ese proveedor como es ajeno y probablemente de soporte para otros muchos servicios no podemos hacer que cumpla un contrato explícito.

En su lugar, el archivo que genera nuestro consumidor mediante la ejecucción de los test esperando que se cumpla un contrato determinado se valida contra la salida de un de doble de test que simula ser el proveedor real. En este caso es importante que configuremos algún tipo de alerta que nos avisa cuando el proveedor real cambia su salida para que nosotros la actualicemos en nuestro proveedor falso. Recalcar que en este caso el falso proveedor se encuentra integrado dentro del mismo artefacto donde está el consumidor. El punto negativo de este método es que cuando el proveedor cambie el mensaje que publica, hará que nuestro código falle hasta que nuestra batería de test se lancen y se vuelva a comprobar que se cumple el contrato, algo que no se estaría cumpliendo y por lo tanto tendríamos que actualizar el contrato que espera nuestro consumidor.

Ventajas de Consumer Driven Contract Testing

¿Qué ganamos con el uso de una herramienta como esta? Pues evitamos que tener que hacer test end to end muy costosos para verificar que la integración entre nuestros microservicios funciona correctamente. Nos ahorra mantener el entorno de ejecucción que levantamos para los test end to end. Recibimos feedback más rápido.

Como único problema de este tipo de contract testing es que representa un entorno simulado, mientras que un test end to end representa un entorno más real, por lo que depende del caso según el tipo de integración que estemos intentando testear, puede que nos salga más a cuenta para ir más seguros a producción los test end to end, pero lo dicho, para una comunicación básica entre servicios basada en mensajes o vía API sale muy rentable utilizar consumer driven contract testing.

Herramientas para su uso

Pact es una herramienta de prueba de contratos impulsada por el consumidor que genera contratos explícitos mediante el uso de un doble de prueba que registra las solicitudes y las respuestas esperadas a un contrato que se denomina «pacto», el ‘contrato’ del que hablabamos anteriormente.

Durante la ejecucción de los test del consumidor se realiza una solicitud al proveedor simulado de Pact que registra en el archivo del contrato junto con su respuesta esperada. Con esto hemos garantizado que desde el lado del consumidor se sigue cumpliendo el contrato. Tras esto, una simulación del consumir que nos provee Pact vuelve a ejecutar una solicitud, pero esta vez contra el proveedor real y compara la respuesta actual con la esperada. Si la salida del consumidor simulado es igual a la real se cumple el contrato por parte del proveedor. Entonces, tras haberse cumplido el contrato por ambas partes nos hemos asegurado que nuestros dos servicios, proveedor y consumidor, se comunicarán correctamente en el entorno real, véase producción.

Consumer Driven Contract Testing + Continuous Integration/Continuous Deployment

La guinda en el pastel es que automaticemos el uso de Contract Testing haciendo que se integre en nuestro CI/CD, asegurándonos así que con cada build se ejecute y que nos permita deployar solo si el contrato se cumple. En el caso de que utilicemos Pact como nuestra herramienta para contract testing será necesario configurar Pact Broker, una aplicación para compartir contratos impulsados por el consumidor. Está optimizado para su uso con «pactos» (contratos creados por el framework Pact), pero puede utilizarse para cualquier tipo de contrato que pueda serializarse en JSON ¿Y qué ganamos usando esto? El Pact Broker permite desacoplar fácilmente el ciclo de lanzamiento de Consumer y Provider, unificando en un solo punto los resultado obtenidos y demás información interesante sobre el pacto, como pueda ser documentación entre otros detalles. Quizás como único inconveniente es que Pact Brocker al ser Open Source es self hosting, por lo que otra alternativa puede ser Pactflow, un fork de Pact Broker que ofrece una serie de ventajas sobre su padre que las que podemos destacar que está pensada para equipos ofreciendo una mejor interfaz de usuario, almacenamiento a cargo de la aplicación, una gran mejora en seguridad en lo que se refiera a inicio de sesión, y demás features que se pueden seguir destacando.

Para que puedas realizar o ver un ejemplo práctico te recomiendo seguir el workshop creado por la propia gente de Pactflow en el que detallan como realizar Consumer Driven Contract Testing e integrarlo con CI/CD. Ver el siguiente enlace: Pactflow Workshop - CI/CD

Creado con Hugo
Tema Stack diseñado por Jimmy