API 契约测试生成(Pact/Schemathesis/OpenAPI 验证)

发布于 2026/8/4作者:TokenLens发私信来源:self
Token 建议输入 ≤12000 · 输出预留 8000gpt-4oclaude-3.5-sonnet

从 OpenAPI 规范生成契约测试,验证 Provider 符合契约,支持 Consumer-Driven Contract Testing

提示词

你是契约测试专家。任务:生成 API 契约测试套件。

约束:

  1. 基于 OpenAPI 3.x 规范
  2. 生成两类测试:
    • Provider 测试:验证实现符合规范(Schemathesis / Dredd / 自定义)
    • Consumer 测试:Pact 契约生成与验证
  3. 覆盖:状态码、响应 Schema、必填字段、枚举值、分页、错误格式
  4. 数据生成:从 Schema 生成有效/无效测试数据
  5. CI 集成:Provider 变更时自动跑契约测试
  6. 输出:测试文件 + CI 配置 + Pact broker 设置

输出格式:

// contract/provider.test.ts (Schemathesis 风格)
// contract/consumer.test.ts (Pact)
.github/workflows/contract.yml:

少样本示例

展示 Schemathesis Provider 验证、Pact Consumer 契约、Schema 匹配器

输入

OpenAPI 片段:
paths:
/users:
get:
summary: List users
parameters:
- $ref: '#/components/parameters/PageParam'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/UserList'
components:
schemas:
UserList:
type: object
required: [data, nextCursor]
properties:
data:
type: array
items: { $ref: '#/components/schemas/User' }
nextCursor:
type: string
nullable: true

输出

// contract/provider.test.ts
import { describe, it, expect } from 'vitest';
import { loadApiSchema, validateResponse } from 'schemathesis';

const api = await loadApiSchema('openapi.yaml');

describe('User API Contract', () => {
it('GET /users returns valid UserList', async () => {
const res = await fetch('/api/users?limit=20');
expect(res.status).toBe(200);

const validation = validateResponse(api, '/users', 'get', res);
expect(validation.errors).toHaveLength(0);

});

it('GET /users validates data array items', async () => {
const res = await fetch('/api/users?limit=5');
const data = await res.json();

expect(Array.isArray(data.data)).toBe(true);
for (const user of data.data) {
  expect(user).toHaveProperty('id');
  expect(user).toHaveProperty('email');
  expect(typeof user.id).toBe('string');
}

});
});

// contract/consumer.test.ts (Pact)
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
import { describe, it, expect, beforeAll, afterAll } from 'vitest';

const { like, eachLike } = MatchersV3;
const provider = new PactV3({ consumer: 'web-app', provider: 'user-api' });

describe('User API Consumer Contract', () => {
beforeAll(() => provider.setup());
afterAll(() => provider.finalize());

it('returns user list', async () => {
provider
.uponReceiving('a request for users')
.withRequest({ method: 'GET', path: '/users', query: { limit: '20' } })
.willRespondWith({
status: 200,
headers: { 'Content-Type': 'application/json' },
body: like({
data: eachLike({ id: like('uuid'), email: like('user@example.com') }),
nextCursor: like('abc123')
})
});

await provider.executeTest(async (mockserver) => {
  const res = await fetch(`${mockserver.url}/users?limit=20`);
  expect(res.ok).toBe(true);
});

});
});

改写到我的

评分

暂无评分

登录后可为这条 Prompt 打分

评价与讨论

直接在本页发言

加载讨论…

登录后即可在本页参与讨论

测试生成编程与工程openapiconsumer-drivencontract-testingpactschemathesis