Implementando Pruebas de Contrato Automatizadas con Pact en Pipelines CI/CD
Este tutorial práctico detalla el proceso completo para integrar pruebas de contrato con Pact en un pipeline de CI/CD, asegurando que la comunicación entre microservicios no se rompa durante los despliegues continuos.
🚀 Introducción a las Pruebas de Contrato en Arquitecturas Modernas
En las arquitecturas de microservicios actuales, la velocidad de entrega es fundamental. Sin embargo, a medida que el número de servicios crece, también lo hace la complejidad de las integraciones. Los métodos tradicionales de pruebas de integración end-to-end (E2E) suelen ser lentos, frágiles y costosos de mantener en entornos de integración continua (CI/CD).
Aquí es donde entran en juego las pruebas de contrato. Un contrato es un acuerdo entre un servicio consumidor y un servicio proveedor que define cómo deben estructurarse las solicitudes y las respuestas HTTP. Al validar estos contratos de forma independiente en el pipeline, garantizamos la compatibilidad sin necesidad de levantar todo el ecosistema de servicios.
🛠️ ¿Qué es Pact y Cómo Funciona?
Intermedio Microservicios
Pact es un framework de pruebas de contrato dirigido por el consumidor (Consumer-Driven Contracts). Esto significa que el consumidor de la API define sus expectativas en un archivo JSON (el contrato o pacto), el cual es verificado posteriormente por el proveedor.
El flujo general sigue estos pasos:
📦 Configuración del Consumidor y Generación del Contrato
Comenzaremos configurando el lado del consumidor. Para este ejemplo, utilizaremos Node.js con Jest y la librería Pact.
Primero, instalamos las dependencias necesarias en el proyecto del consumidor:
npm install @pact-foundation/pact --save-dev
npm install jest --save-dev
A continuación, creamos una prueba que defina las expectativas del consumidor sobre un servicio de usuarios:
const { Pact } = require('@pact-foundation/pact');
const path = require('path');
const { fetchUserById } = require('./userClient');
const provider = new Pact({
consumer: 'ConsumerService',
provider: 'UserService',
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
dir: path.resolve(process.cwd(), 'pacts'),
logLevel: 'INFO',
});
describe('API de Usuario - Pruebas de Contrato', () => {
beforeAll(() => provider.setup());
afterEach(() => provider.verify());
afterAll(() => provider.finalize());
describe('cuando se solicita un usuario existente', () => {
beforeEach(() => {
const interaction = {
state: 'un usuario con ID 1 existe',
uponReceiving: 'una petición GET para obtener el usuario 1',
withRequest: {
method: 'GET',
path: '/users/1',
},
willRespondWith: {
status: 200,
headers: {
'Content-Type': 'application/json',
},
body: {
id: 1,
name: 'Juan Pérez',
email: 'juan@example.com',
},
},
};
return provider.addInteraction(interaction);
});
it('retorna el objeto de usuario correcto', async () => {
const response = await fetchUserById('http://localhost:1234', 1);
expect(response.name).toEqual('Juan Pérez');
});
});
});
🔄 Integrando el Consumidor en el Pipeline de CI/CD
Una vez que las pruebas del consumidor pasan exitosamente, el pipeline de CI debe generar el archivo JSON del contrato y publicarlo en el Pact Broker.
A continuación, se muestra un ejemplo de un pipeline utilizando GitHub Actions para el servicio consumidor:
name: CI Consumidor
on: [push]
jobs:
test-and-publish:
runs-on: ubuntu-latest
steps:
- name: Clonar repositorio
uses: actions/checkout@v3
- name: Configurar Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Instalar dependencias
run: npm ci
- name: Ejecutar pruebas de contrato
run: npm run test:pact
- name: Publicar contratos en Pact Broker
env:
PACT_BROKER_BASE_URL: https://tu-pact-broker.baseurl.com
PACT_BROKER_TOKEN: ${{ secrets.PACT_BROKER_TOKEN }}
run: |
npx pact-broker publish ./pacts \
--broker-base-url=$PACT_BROKER_BASE_URL \
--broker-token=$PACT_BROKER_TOKEN \
--consumer-app-version=${{ github.sha }}
🔍 Verificación del Contrato en el Proveedor
Del lado del proveedor (UserService), el pipeline de CI/CD debe descargar los contratos publicados por sus consumidores y verificar que la implementación actual de la API cumple con dichas expectativas.
Crearemos un script de verificación en el proveedor usando Node.js:
const { Verifier } = require('@pact-foundation/pact');
const path = require('path');
describe('Verificación de Contratos Pact', () => {
it('valida las expectativas del consumidor', () => {
const opts = {
provider: 'UserService',
providerBaseUrl: 'http://localhost:8080',
pactBrokerUrl: process.env.PACT_BROKER_BASE_URL,
pactBrokerToken: process.env.PACT_BROKER_TOKEN,
publishVerificationResult: true,
providerVersion: process.env.GITHUB_SHA,
};
return new Verifier(opts).verifyProvider().then(() => {
console.log('¡Verificación de Pact exitosa!');
});
});
});
🛡️ Control de Can-I-Deploy: Seguridad en el Despliegue
Uno de los mayores beneficios de usar un Pact Broker es la capacidad de responder a la pregunta: ¿Puedo desplegar este servicio de manera segura sin romper la producción?
Antes de realizar un despliegue a producción, el pipeline de CI/CD debe ejecutar la herramienta CLI de Pact para verificar la compatibilidad:
npx pact-broker can-i-deploy \
--pactee=UserService \
--version=v1.2.3 \
--to-environment=production \
--broker-base-url=https://tu-pact-broker.baseurl.com \
--broker-token=$PACT_BROKER_TOKEN
Si algún consumidor ha publicado un contrato incompatible y el proveedor aún no lo soporta, este comando fallará, deteniendo automáticamente el despliegue y previniendo interrupciones en producción.
can-i-deploy debe ser un paso obligatorio y bloqueante en cualquier pipeline de despliegue continuo para arquitecturas basadas en microservicios.❓ Preguntas Frecuentes (FAQ)
¿Qué pasa si modifico una API que no tiene consumidores?
Si realizas cambios en una ruta que ningún consumidor está probando mediante contratos, las pruebas de Pact seguirán pasando con normalidad. Sin embargo, se recomienda añadir un nuevo contrato si la ruta va a ser utilizada próximamente.¿Puedo usar Pact con servicios que no sean HTTP (como gRPC o mensajería)?
Sí, Pact soporta pruebas basadas en mensajes (Message Pact) para colas de eventos como RabbitMQ, Kafka o AWS SQS, además de soporte avanzado para gRPC.📈 Resumen y Próximos Pasos
Las pruebas de contrato automatizadas transforman la forma en que los equipos despliegan microservicios, reduciendo drásticamente los tiempos de los pipelines de CI/CD en comparación con las pruebas E2E tradicionales. Al integrar Pact y un Pact Broker, obtienes visibilidad total sobre las dependencias y la confianza necesaria para desplegar de forma independiente.
Para seguir mejorando tus pipelines:
- Explora la implementación de Message Pacts si utilizas arquitecturas orientadas a eventos.
- Configura webhooks en tu Pact Broker para disparar pipelines de verificación automáticamente cuando un consumidor actualice su contrato.
Tutoriales relacionados
- Gestionando Feature Flags con LaunchDarkly en Pipelines CI/CDintermediate18 min
- Gestionando la Configuración de Entornos con Consul y Vault en Pipelines CI/CDintermediate20 min
- Implementando Blue/Green Deployments con Kubernetes y GitOps para CI/CD sin Downtimeintermediate20 min
- Despliegues Canario con Istio y Kubernetes: Controlando el Riesgo en CI/CDintermediate20 min
- Observabilidad en Pipelines CI/CD con OpenTelemetry: Monitoreo Unificado y Trazabilidad Extremaintermediate20 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!