API契约测试 api-contract-testing

API契约测试是一种软件测试技能,专注于验证服务间API接口是否符合预定义的契约,以确保微服务通信的准确性、兼容性和可靠性。它使用消费者驱动的契约测试、模式验证(如OpenAPI和JSON Schema)和工具如Pact来防止破坏性变更,支持持续集成和部署。关键词:API测试、契约测试、微服务、Pact、OpenAPI、消费者驱动、模式验证、软件测试、集成测试。

测试 0 次安装 0 次浏览 更新于 3/8/2026

name: api-contract-testing description: 使用消费者驱动的契约、模式验证和如Pact等工具验证服务间的API契约。在测试微服务通信、防止破坏性变更或验证OpenAPI规范时使用。

API契约测试

验证API在消费者和提供者之间遵守其契约,无需完整的集成测试。

关键概念

术语 定义
消费者 调用API的服务
提供者 暴露API的服务
契约 约定的请求/响应格式
Pact 消费者驱动的契约测试工具
模式 结构定义(OpenAPI, JSON Schema)
代理 契约的中央存储库

Pact消费者测试(TypeScript)

import { PactV3, MatchersV3 } from '@pact-foundation/pact';

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

describe('User API Contract', () => {
  it('returns user by ID', async () => {
    await provider
      .given('user 123 exists')
      .uponReceiving('a request for user 123')
      .withRequest({ method: 'GET', path: '/users/123' })
      .willRespondWith({
        status: 200,
        body: MatchersV3.like({
          id: '123',
          name: MatchersV3.string('John'),
          email: MatchersV3.email('john@example.com')
        })
      })
      .executeTest(async (mockServer) => {
        const response = await fetch(`${mockServer.url}/users/123`);
        expect(response.status).toBe(200);
      });
  });

  it('returns 404 for non-existent user', async () => {
    await provider
      .given('user does not exist')
      .uponReceiving('a request for non-existent user')
      .withRequest({ method: 'GET', path: '/users/999' })
      .willRespondWith({
        status: 404,
        body: MatchersV3.like({
          error: { code: 'NOT_FOUND', message: MatchersV3.string() }
        })
      })
      .executeTest(async (mockServer) => {
        const response = await fetch(`${mockServer.url}/users/999`);
        expect(response.status).toBe(404);
      });
  });
});

提供者验证

import { Verifier } from '@pact-foundation/pact';

new Verifier({
  provider: 'UserService',
  providerBaseUrl: 'http://localhost:3000',
  pactBrokerUrl: process.env.PACT_BROKER_URL,
  publishVerificationResult: true,
  providerVersion: process.env.GIT_SHA,
  stateHandlers: {
    'user 123 exists': async () => {
      await db.users.create({ id: '123', name: 'John' });
    },
    'user does not exist': async () => {
      await db.users.deleteAll();
    }
  }
}).verifyProvider();

OpenAPI验证(Express)

const OpenApiValidator = require('express-openapi-validator');

app.use(OpenApiValidator.middleware({
  apiSpec: './openapi.yaml',
  validateRequests: true,
  validateResponses: true,
  validateSecurity: true
}));

其他实现

最佳实践

做:

  • 从消费者角度测试
  • 使用匹配器进行灵活匹配
  • 验证结构,而非特定值
  • 明确版本化契约
  • 测试错误响应
  • 在CI管道中运行测试
  • 测试向后兼容性

不做:

  • 在契约中测试业务逻辑
  • 硬编码特定值
  • 跳过错误场景
  • 忽略版本控制
  • 未经验证部署

工具

  • Pact - 多语言消费者驱动的契约
  • Spring Cloud Contract - JVM生态系统
  • OpenAPI/Swagger - 模式优先验证
  • Dredd - API蓝图测试
  • Spectral - OpenAPI代码检查