En pocas palabras
Herramienta de contract testing en la que el consumidor registra sus expectativas sobre una API en un contrato, y el proveedor lo verifica contra su implementación real.
Qué problema resuelve
Pruebas end-to-end lentas y frágiles en entornos compartidos, o cambios de API que rompen a consumidores sin que nadie lo detecte antes de producción.
Cuándo utilizarlo
Servicios que se comunican por HTTP o mensajes y se despliegan de forma independiente. Ejemplo: la app móvil y la API de solicitudes evolucionan en equipos distintos.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
Cómo funciona
- Consumidor: una prueba unitaria define la interacción esperada (petición y respuesta mínima) contra un mock de Pact. Al pasar, se genera un archivo de contrato (pact).
- Broker: el contrato se publica en un Pact Broker (o PactFlow) asociado a la versión y rama del consumidor.
- Proveedor: su pipeline descarga los contratos relevantes y los reproduce contra la API real, preparando el estado necesario.
- can-i-deploy: antes de desplegar, cualquiera de los dos pregunta al broker si la versión es compatible con lo que hay en el entorno destino.
Ejemplo de prueba del consumidor (JavaScript)
import { PactV4, MatchersV3 } from '@pact-foundation/pact';
const { like, string } = MatchersV3;
const provider = new PactV4({
consumer: 'app-movil',
provider: 'api-solicitudes',
});
it('obtiene el estado de una solicitud', () =>
provider
.addInteraction()
.given('existe la solicitud 42 en evaluación')
.uponReceiving('una consulta de estado')
.withRequest('GET', '/v1/solicitudes/42')
.willRespondWith(200, (b) =>
b.jsonBody({ id: string('42'), estado: like('EN_EVALUACION') }),
)
.executeTest(async (mock) => {
const res = await obtenerEstado(mock.url, '42');
expect(res.estado).toBe('EN_EVALUACION');
}));
like verifica el tipo, no el valor exacto, para que el contrato no sea frágil. El texto de given es el provider state que el proveedor debe saber preparar.
Verificación en el proveedor y despliegue
pact-broker can-i-deploy \
--pacticipant api-solicitudes --version "$GIT_SHA" \
--to-environment produccion
Tras desplegar, se registra con record-deployment para que el broker conozca qué versiones conviven en cada entorno.
Cuándo no usarlo
- APIs públicas con consumidores desconocidos: mejor esquemas versionados (OpenAPI) y pruebas de compatibilidad.
- Equipos que no controlan al proveedor (SaaS externos).
- Para validar lógica de negocio del proveedor: el contrato prueba la forma de la integración, no las reglas.
Verificación del proveedor con Spring Boot
@Provider("api-solicitudes")
@PactBroker // URL y credenciales por propiedades o variables de entorno
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ContratosProveedorTest {
@LocalServerPort int puerto;
@Autowired SolicitudRepository repo;
@BeforeEach
void destino(PactVerificationContext ctx) {
ctx.setTarget(new HttpTestTarget("localhost", puerto));
}
@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider.class)
void verificarInteracciones(PactVerificationContext ctx) {
ctx.verifyInteraction();
}
@State("existe la solicitud 42 en evaluación")
void solicitud42() {
repo.save(Solicitud.enEvaluacion("42"));
}
}
Cada @State corresponde a un given(...) del consumidor. El proveedor prepara sus propios datos; no hace falta un entorno compartido con datos «mágicos».
Contratos de mensajes (Kafka, Pub/Sub)
Pact también verifica eventos asíncronos: el consumidor declara qué forma de mensaje espera y el proveedor demuestra que es capaz de producirlo, sin un broker real en la prueba.
| Lado | Qué prueba |
|---|---|
| Consumidor | Que su handler procesa correctamente un mensaje con esa forma |
| Proveedor | Que la función que construye el evento genera un mensaje compatible |
Complementa (no sustituye) al registro de esquemas: el registro impone compatibilidad técnica del esquema completo; Pact verifica lo que cada consumidor usa realmente.
Flujo con ramas y entornos
PR en consumidor ── publica contrato (versión = SHA, rama) ──► Broker
│ webhook
Proveedor ◄── ejecuta verificación del contrato nuevo ─────────┘
│ publica resultado
▼
can-i-deploy (consumidor) → ¿compatible con lo que hay en producción? → desplegar
record-deployment → el broker sabe qué versión está en cada entorno
Con pending pacts y WIP pacts, un contrato nuevo de un consumidor no rompe el build del proveedor hasta que se ha verificado una vez, lo que evita bloqueos entre equipos.
Errores frecuentes
- Contratos que copian respuestas completas: cualquier cambio del proveedor los rompe.
- Usar Pact para probar reglas de negocio del proveedor.
- No ejecutar
can-i-deploy: los contratos se verifican pero nadie impide desplegar una versión incompatible.
Criterios de implementación
Empieza por la integración que más se rompe. Mantén los contratos mínimos y sin datos específicos. Integra can-i-deploy como paso bloqueante del pipeline y usa ramas y entornos en el broker. Es una buena fitness function de evolución de API y reduce dependencia de pruebas end-to-end.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.