合同API测试
1)为什么要进行合同测试
该合同记录了客户的期望和提供商的承诺:路线/方法,标题,身体模式,状态,错误语义和约束。目的是在集成之前捕获不兼容的更改,并安全发布版本,而无需重E2E。
2)方法
消费驱动合同(CDC):客户形成期望(Pact和类似物);提供商定期对其进行验证。
规格:作为单一真理来源的合同(OpenAPI/Protobuf/GraphQL SDL);测试验证实现与规范。
事件:消息模式(Avro/JSON Schema/Protobuf)+经纪人/注册表中的互操作性规则。
3) HTTP/REST: 规格流
1.合同:OpenAPI 3。x(模式、示例、代码)。
2.Lint和统计分析:样式,必填字段,统一代码。
3.实现验证:测试生成器与OpenAPI (schemathesis/Dredd方法)+手动底片。
4.Snapshots:捕捉示例响应,ETag语义,同位性标题。
yaml paths:
/v1/payments:
post:
responses:
"201": { $ref: "#/components/responses/PaymentCreated" }
"409": { description: Duplicate by Idempotency-Key }
"422": { description: Schema/Business validation failed }
4)CDC(Pact方法)
生命周期:1.消费者编写测试,形成pact文件(期望)。
2.发布到经纪人(工件)。
3.CI的Provider提升服务(或合同柜台),验证pact 's。
4.经纪人计算can-i-deploy兼容性矩阵。
消费者测试(伪JS)的示例:js pact
.given("wallet exists")
.uponReceiving("get wallet")
.withRequest({ method:"GET", path:"/v1/wallets/w123", headers:{ "Authorization": term({generate:"Bearer x", matcher:/^Bearer\s.+/}) }})
.willRespondWith({
status: 200,
headers: { "Content-Type": "application/json" },
body: like({ id:"w123", currency: "EUR", balance: 0 })
});
5) gRPC/Protobuf合同
合同是".proto",其中包含数据包/服务的版本。
兼容性:不要重新使用标签,只添加新的选项,不删除使用的字段;预留号码。
测试:生成服务器/客户机稳定,租用自动生成的桉例+底片(未知领域,尺寸限制)。
6)事件合同(Kafka/NATS/……)
Схемы: Avro/JSON Schema/Protobuf в Schema Registry.
兼容性策略:"BACKWARD"(通常足够)或"FULL"。
Prodewser测试:验证针对方案的信息;消费者测试:接受新旧版本。
不变性:等速键、顺序/可重复性、重复数据消除语义。
json
{"type":"record","name":"PayoutCreated","fields":[
{"name":"payoutId","type":"string"},
{"name":"amount","type":"double"},
{"name":"currency","type":{"type":"string","logicalType":"iso-4217"}}
]}
7)兼容性和版本
Backward-copatible(建议的最低限度):添加可选字段,不要打破现有字段。
前瞻性:消费者忽略未知领域。
满:两者。
转化: "path (/v1)"、"Accept: application/vnd"。brand.v2+json`, `proto package v2`.
Deprecation策略:输出窗口(例如90天),警告标题/事件。
8)负面和错误也是合同
标准化代码:400/401/403/404/409/422/429/5xx,必填字段"code","message","trace_id"。
尺寸/限额是合同的一部分(413/414/431)。
等效性:重复行为(409 vs 201 same id)。
标题:429/503的"Retry-After","Idempotency-Key","Content-Language"等。
json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"..." }
9)数据管理合同
示例/试衣间响应(examples)是活的,在CI中得到验证。
CDC的fixturs是最小的,确定性的。
数据生成-基于数字/日期的属性;但不要破坏狙击手的稳定性。
10)CI/CD中的管道(参考)
1.Lint/validate: OpenAPI/Proto/Avro (`validate`, style-линер).
2.出版物:作为文物的合同(经纪人/登记处)。
3.验证:提供商运行CDC数据包/规范测试。
4.can-i-deploy门:没有绿色矩阵,不允许发布。
5.Diff:验证更改是否兼容(semantic diff)。
6.报告:JUnit/HTML,违规行为/定义列表。
yaml jobs:
lint:...
publish-contract: needs: [lint]
verify-provider: needs: [publish-contract]
can-i-deploy:
if: always()
steps: [run: pact-broker can-i-deploy...]
11)工具(按任务类)
Lint/验证器:openapi-linters,protobuf-lint,avro-tools。
CDC:pact家族/经纪人,Spring Cloud Contract,Hoverfly(HTTP记录/反射)。
规格先行者:schemathesis/Dredd样方法,Postman test+JSON Schema。
Diff: semantic-diff OpenAPI/Proto/Avro(显示断开更改)。
容器:Testcontainers提升供应商/合同柜台。
12)反模式
"Spetz-dock"与代码分开→同步。将合同存储在服务附近。
第三方服务的洗涤代替合同→升级时的脆弱性。
随机响应/生成而不涉及长笛→模式。
更改字段的类型/强制性而不修改版本。
无通知/撤消的静音扩展。
没有负面合同和错误代码。
13) iGaming/财务细节
将货币字段正式化:"amount"-具有比例的贬值,货币是ISO-4217和不变量。
支付/webhook合同:HMAC/mTLS,反重播("X-Timestamp"窗口),等效性,"Retry-After"。
区域/特南特:强制性标题"X-Tenant/X-Region",消息本地化。
事件:不变日志(审核),重复数据消除密钥,交付保证(at least once+idemented hendler)。
14)测试的"骨架"示例
14.1 Schemathesis风格(伪造的)
bash schemathesis run openapi. yaml --checks all --hypothesis-deadline=200
14.2 Postman作为规范运行者
js pm. test ("Scheme/v1/wallets/{ id} is valid," () => {
const schema = pm. collectionVariables. get("wallet_get_schema");
pm. expect(ajv. validate(JSON. parse(schema), pm. response. json())). to. be. true;
});
14.3 Provider验证CDC(伪)
bash pact-broker can-i-deploy --pacticipant wallets --version $SHA --to-environment staging
15)准备就绪支票清单
- 存储库中的合同,CI验证和发布文物。
- CDC用于关键集成;broker/matrix "can-i-deploy"正在运行。
- 兼容性策略(HTTP/gRPC/Events)已得到记录;自动semantic-diff。
- 负面合同:错误,尺寸限制,相等性,"Retry-After"。
- 测试数据是确定性的;支持示例快照。
[……]核查和执行:时间、通知、标题。
- 对于事件-计划注册和兼容模式;生产者/消费者测试这两个版本。
- 工件:JUnit/HTML,报告diff/verify,兼容性矩阵。
- 事件过程:快速回滚合同/远距标志,通知集成商。
16) TL;DR
将期望值捕获到合同中并自动运行:用于客户期望的CDC、用于实现的规范测试、用于事件的模式注册表。保持严格的兼容性政策和负面合同(错误、限制、等效性)。如果没有绿色can-i-deploy矩阵和半空格,则无需进行突破性更改即可发布。