¿Por Qué Contract Testing?

En microservicios, los servicios se desarrollan y despliegan independientemente. Sin contract testing, dependes de integration tests (lentos y frágiles), documentación (puede estar desactualizada) o esperanza.

Contract testing verifica que los servicios pueden comunicarse correctamente sin necesitar que todos estén ejecutándose al mismo tiempo.

Cómo Funciona Pact

Pact usa un enfoque consumer-driven: el consumidor define lo que espera, Pact genera un contrato, el proveedor lo verifica.

Escribiendo Tests de Consumidor

const { PactV3, MatchersV3 } = require('@pact-foundation/pact');
const { like, string, integer } = MatchersV3;

const provider = new PactV3({
  consumer: 'OrderService',
  provider: 'UserService',
});

describe('UserService contrato', () => {
  test('obtener usuario por ID', async () => {
    await provider
      .given('usuario con ID 123 existe')
      .uponReceiving('solicitud para usuario 123')
      .withRequest({ method: 'GET', path: '/users/123' })
      .willRespondWith({
        status: 200,
        body: {
          id: integer(123),
          name: string('Alice'),
          email: string('alice@example.com'),
        },
      });

    await provider.executeTest(async (mockServer) => {
      const userClient = new UserClient(mockServer.url);
      const user = await userClient.getUser(123);
      expect(user.id).toBe(123);
    });
  });
});

Escribiendo Tests de Proveedor

const { Verifier } = require('@pact-foundation/pact');

describe('UserService verificación de proveedor', () => {
  test('verifica todos los contratos', async () => {
    const verifier = new Verifier({
      providerBaseUrl: 'http://localhost:3001',
      pactBrokerUrl: 'https://your-broker.pact.io',
      provider: 'UserService',
      stateHandlers: {
        'usuario con ID 123 existe': async () => {
          await db.users.create({ id: 123, name: 'Alice', email: 'alice@example.com' });
        },
      },
    });
    await verifier.verifyProvider();
  });
});

Matchers de Pact

Los matchers hacen los contratos flexibles: like() para tipo, string() para strings, integer() para enteros, eachLike() para arrays, regex() para patrones.

Pact Broker

Repositorio central para contratos. El comando can-i-deploy responde: “¿es seguro desplegar esta versión?”

Ejercicio: Implementación de Contract Testing

Tarea 1: Tests de Contrato del Consumidor

Escribe tests para un OrderService que consume un ProductService API con 4 interacciones.

Tarea 2: Verificación del Proveedor

Escribe tests de proveedor con state handlers para cada estado “given”.

Tarea 3: Integración con Pact Broker

Configura Pact Broker local, publica contratos, configura verificación del proveedor, usa can-i-deploy.

Tarea 4: Detección de Breaking Changes

Haz un breaking change, ejecuta verificación, documenta la falla, corrige.

Tarea 5: Integración en Pipeline CI

Diseña pipeline: Consumer CI publica contratos, Provider CI los verifica.

Entregables

  1. Código de tests de consumidor con al menos 4 interacciones.
  2. Código de verificación de proveedor con state handlers.
  3. Configuración de Pact Broker.
  4. Documento de diseño de pipeline CI.
  5. Demostración de detección de breaking changes.