tutoriales.com

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.

Intermedio8 min de lectura13 views
Reportar error

🚀 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.

💡 Consejo: Las pruebas de contrato no reemplazan a las pruebas unitarias ni a las de integración profunda, pero eliminan la necesidad de pruebas E2E masivas y lentas en las etapas tempranas del pipeline.

🛠️ ¿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:

Paso 1: El consumidor escribe una prueba unitaria usando Pact que define el comportamiento esperado del proveedor.
Paso 2: Se genera un archivo de contrato JSON localmente en el repositorio del consumidor.
Paso 3: El consumidor publica el contrato en un servidor centralizado (Pact Broker).
Paso 4: El proveedor descarga el contrato en su propio pipeline de CI y verifica que cumple con las expectativas.
Arquitectura de Pact Broker Consumidor 1. Genera Contrato pacto.json (Pruebas Unitarias) Pact Broker Repositorio de Contratos Versionado Proveedor 3. Pipeline de CI Verificación PUBLICAR DESCARGAR RESULTADOS Flujo: El Consumidor publica su contrato al Broker. El Proveedor lo descarga en su CI, lo valida contra su implementación y notifica el resultado al Broker.

📦 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');
    });
  });
});
⚠️ Advertencia: Asegúrate de que el puerto configurado en el objeto Pact no colisione con otros servicios que se ejecuten durante tus pruebas locales o en el servidor de CI.

🔄 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!');
    });
  });
});
Pact Broker (Repositorio de Contratos) Pipeline Proveedor (Orquestador de CI/CD) API Proveedor (SUT) 1. Consulta Contratos 2. Ejecuta Verificación 3. Reporta Resultados Flujo de Validación Cruzada (Provider Side)

🛡️ 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.

🔥 Importante: El comando 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

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!