文章目录
- [20 接口契约测试 - 前后端的"合同"](#20 接口契约测试 - 前后端的"合同")
-
- [20.1 什么是契约测试](#20.1 什么是契约测试)
- [20.2 为什么需要契约测试](#20.2 为什么需要契约测试)
- [20.3 Swagger/OpenAPI](#20.3 Swagger/OpenAPI)
- [20.4 Pact契约测试](#20.4 Pact契约测试)
- [20.5 契约测试最佳实践](#20.5 契约测试最佳实践)
- [20.6 本章小结](#20.6 本章小结)
-
- 契约测试核心
- [课后练习 📝](#课后练习 📝)
- [20.7 下章预告](#20.7 下章预告)
20 接口契约测试 - 前后端的"合同"
🎯 本章目标:理解契约测试的概念,掌握Swagger和Pact的使用,学会保障前后端接口一致性。
20.1 什么是契约测试
生活中的类比
想象你请装修公司装修房子:
你(前端)和装修公司(后端)签订了一份合同(契约):
- 客厅要铺什么地板(接口字段)
- 墙面刷什么颜色(数据格式)
- 工期多久(响应时间)
契约测试 = 检查装修公司是否按合同施工
契约测试定义
契约测试(Contract Testing):验证服务提供者(Provider)和服务消费者(Consumer)之间的接口契约是否被遵守。
#mermaid-svg-kCMIagmHxKaqnnBI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kCMIagmHxKaqnnBI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kCMIagmHxKaqnnBI .error-icon{fill:#552222;}#mermaid-svg-kCMIagmHxKaqnnBI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kCMIagmHxKaqnnBI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kCMIagmHxKaqnnBI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kCMIagmHxKaqnnBI .marker.cross{stroke:#333333;}#mermaid-svg-kCMIagmHxKaqnnBI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kCMIagmHxKaqnnBI p{margin:0;}#mermaid-svg-kCMIagmHxKaqnnBI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kCMIagmHxKaqnnBI .cluster-label text{fill:#333;}#mermaid-svg-kCMIagmHxKaqnnBI .cluster-label span{color:#333;}#mermaid-svg-kCMIagmHxKaqnnBI .cluster-label span p{background-color:transparent;}#mermaid-svg-kCMIagmHxKaqnnBI .label text,#mermaid-svg-kCMIagmHxKaqnnBI span{fill:#333;color:#333;}#mermaid-svg-kCMIagmHxKaqnnBI .node rect,#mermaid-svg-kCMIagmHxKaqnnBI .node circle,#mermaid-svg-kCMIagmHxKaqnnBI .node ellipse,#mermaid-svg-kCMIagmHxKaqnnBI .node polygon,#mermaid-svg-kCMIagmHxKaqnnBI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kCMIagmHxKaqnnBI .rough-node .label text,#mermaid-svg-kCMIagmHxKaqnnBI .node .label text,#mermaid-svg-kCMIagmHxKaqnnBI .image-shape .label,#mermaid-svg-kCMIagmHxKaqnnBI .icon-shape .label{text-anchor:middle;}#mermaid-svg-kCMIagmHxKaqnnBI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kCMIagmHxKaqnnBI .rough-node .label,#mermaid-svg-kCMIagmHxKaqnnBI .node .label,#mermaid-svg-kCMIagmHxKaqnnBI .image-shape .label,#mermaid-svg-kCMIagmHxKaqnnBI .icon-shape .label{text-align:center;}#mermaid-svg-kCMIagmHxKaqnnBI .node.clickable{cursor:pointer;}#mermaid-svg-kCMIagmHxKaqnnBI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kCMIagmHxKaqnnBI .arrowheadPath{fill:#333333;}#mermaid-svg-kCMIagmHxKaqnnBI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kCMIagmHxKaqnnBI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kCMIagmHxKaqnnBI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kCMIagmHxKaqnnBI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kCMIagmHxKaqnnBI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kCMIagmHxKaqnnBI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kCMIagmHxKaqnnBI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kCMIagmHxKaqnnBI .cluster text{fill:#333;}#mermaid-svg-kCMIagmHxKaqnnBI .cluster span{color:#333;}#mermaid-svg-kCMIagmHxKaqnnBI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kCMIagmHxKaqnnBI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kCMIagmHxKaqnnBI rect.text{fill:none;stroke-width:0;}#mermaid-svg-kCMIagmHxKaqnnBI .icon-shape,#mermaid-svg-kCMIagmHxKaqnnBI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kCMIagmHxKaqnnBI .icon-shape p,#mermaid-svg-kCMIagmHxKaqnnBI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kCMIagmHxKaqnnBI .icon-shape .label rect,#mermaid-svg-kCMIagmHxKaqnnBI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kCMIagmHxKaqnnBI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kCMIagmHxKaqnnBI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kCMIagmHxKaqnnBI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 契约
消费者 Consumer
前端/App
提供者 Provider
后端服务
契约测试
验证消费者请求
验证提供者响应
20.2 为什么需要契约测试
前后端分离的问题
#mermaid-svg-jq7Q3RPnPfaxTC7y{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jq7Q3RPnPfaxTC7y .error-icon{fill:#552222;}#mermaid-svg-jq7Q3RPnPfaxTC7y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jq7Q3RPnPfaxTC7y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .marker.cross{stroke:#333333;}#mermaid-svg-jq7Q3RPnPfaxTC7y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jq7Q3RPnPfaxTC7y p{margin:0;}#mermaid-svg-jq7Q3RPnPfaxTC7y .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster-label text{fill:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster-label span{color:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster-label span p{background-color:transparent;}#mermaid-svg-jq7Q3RPnPfaxTC7y .label text,#mermaid-svg-jq7Q3RPnPfaxTC7y span{fill:#333;color:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .node rect,#mermaid-svg-jq7Q3RPnPfaxTC7y .node circle,#mermaid-svg-jq7Q3RPnPfaxTC7y .node ellipse,#mermaid-svg-jq7Q3RPnPfaxTC7y .node polygon,#mermaid-svg-jq7Q3RPnPfaxTC7y .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .rough-node .label text,#mermaid-svg-jq7Q3RPnPfaxTC7y .node .label text,#mermaid-svg-jq7Q3RPnPfaxTC7y .image-shape .label,#mermaid-svg-jq7Q3RPnPfaxTC7y .icon-shape .label{text-anchor:middle;}#mermaid-svg-jq7Q3RPnPfaxTC7y .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .rough-node .label,#mermaid-svg-jq7Q3RPnPfaxTC7y .node .label,#mermaid-svg-jq7Q3RPnPfaxTC7y .image-shape .label,#mermaid-svg-jq7Q3RPnPfaxTC7y .icon-shape .label{text-align:center;}#mermaid-svg-jq7Q3RPnPfaxTC7y .node.clickable{cursor:pointer;}#mermaid-svg-jq7Q3RPnPfaxTC7y .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .arrowheadPath{fill:#333333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jq7Q3RPnPfaxTC7y .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jq7Q3RPnPfaxTC7y .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jq7Q3RPnPfaxTC7y .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster text{fill:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y .cluster span{color:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jq7Q3RPnPfaxTC7y .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jq7Q3RPnPfaxTC7y rect.text{fill:none;stroke-width:0;}#mermaid-svg-jq7Q3RPnPfaxTC7y .icon-shape,#mermaid-svg-jq7Q3RPnPfaxTC7y .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jq7Q3RPnPfaxTC7y .icon-shape p,#mermaid-svg-jq7Q3RPnPfaxTC7y .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jq7Q3RPnPfaxTC7y .icon-shape .label rect,#mermaid-svg-jq7Q3RPnPfaxTC7y .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jq7Q3RPnPfaxTC7y .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jq7Q3RPnPfaxTC7y .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jq7Q3RPnPfaxTC7y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 前后端分离痛点
接口变更不同步
集成测试太晚
文档不准确
联调成本高
前端按旧接口开发
问题发现晚
文档与代码不一致
反复沟通修改
契约测试的好处
| 好处 | 说明 |
|---|---|
| 早期发现问题 | 开发阶段就发现接口不一致 |
| 独立测试 | 前后端可以独立测试 |
| 文档即代码 | 契约就是接口文档 |
| 自动化保障 | CI/CD中自动验证 |
20.3 Swagger/OpenAPI
什么是Swagger
Swagger/OpenAPI 是一种接口描述规范,用YAML或JSON定义接口的请求、响应、参数等。
Swagger示例
yaml
openapi: 3.0.0
info:
title: 用户管理API
version: 1.0.0
paths:
/api/v1/users:
get:
summary: 获取用户列表
parameters:
- name: page
in: query
schema:
type: integer
default: 1
- name: size
in: query
schema:
type: integer
default: 20
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
code:
type: integer
data:
type: array
items:
$ref: '#/components/schemas/User'
post:
summary: 创建用户
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserInput'
responses:
'201':
description: 创建成功
components:
schemas:
User:
type: object
properties:
id:
type: integer
username:
type: string
email:
type: string
UserInput:
type: object
required:
- username
- email
properties:
username:
type: string
minLength: 3
maxLength: 20
email:
type: string
format: email
Swagger工具
| 工具 | 用途 |
|---|---|
| Swagger Editor | 在线编辑Swagger文档 |
| Swagger UI | 可视化接口文档 |
| Swagger Codegen | 根据文档生成代码 |
20.4 Pact契约测试
什么是Pact
Pact 是一个契约测试框架,支持消费者驱动契约测试(Consumer-Driven Contract Testing)。
Pact工作流程
提供者(后端) Pact Broker 消费者(前端) 提供者(后端) Pact Broker 消费者(前端) #mermaid-svg-MJNuw7L8nAKrwMot{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MJNuw7L8nAKrwMot .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MJNuw7L8nAKrwMot .error-icon{fill:#552222;}#mermaid-svg-MJNuw7L8nAKrwMot .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MJNuw7L8nAKrwMot .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MJNuw7L8nAKrwMot .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MJNuw7L8nAKrwMot .marker.cross{stroke:#333333;}#mermaid-svg-MJNuw7L8nAKrwMot svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MJNuw7L8nAKrwMot p{margin:0;}#mermaid-svg-MJNuw7L8nAKrwMot .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJNuw7L8nAKrwMot text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-MJNuw7L8nAKrwMot .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MJNuw7L8nAKrwMot .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-MJNuw7L8nAKrwMot .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-MJNuw7L8nAKrwMot .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-MJNuw7L8nAKrwMot #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-MJNuw7L8nAKrwMot .sequenceNumber{fill:white;}#mermaid-svg-MJNuw7L8nAKrwMot #sequencenumber{fill:#333;}#mermaid-svg-MJNuw7L8nAKrwMot #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-MJNuw7L8nAKrwMot .messageText{fill:#333;stroke:none;}#mermaid-svg-MJNuw7L8nAKrwMot .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJNuw7L8nAKrwMot .labelText,#mermaid-svg-MJNuw7L8nAKrwMot .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-MJNuw7L8nAKrwMot .loopText,#mermaid-svg-MJNuw7L8nAKrwMot .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-MJNuw7L8nAKrwMot .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-MJNuw7L8nAKrwMot .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-MJNuw7L8nAKrwMot .noteText,#mermaid-svg-MJNuw7L8nAKrwMot .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-MJNuw7L8nAKrwMot .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJNuw7L8nAKrwMot .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJNuw7L8nAKrwMot .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-MJNuw7L8nAKrwMot .actorPopupMenu{position:absolute;}#mermaid-svg-MJNuw7L8nAKrwMot .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-MJNuw7L8nAKrwMot .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-MJNuw7L8nAKrwMot .actor-man circle,#mermaid-svg-MJNuw7L8nAKrwMot line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-MJNuw7L8nAKrwMot :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 编写消费者测试 2. 生成契约文件 3. 编写提供者验证 4. 验证契约 5. 返回验证结果
Python Pact示例
bash
# 安装
pip install pact-python
消费者测试:
python
import requests
from pact import Consumer, Provider
pact = Consumer('frontend').has_pact_with(Provider('userservice'))
@pact.given('用户存在')
.upon_receiving('获取用户信息')
.with_request('GET', '/api/v1/users/1')
.will_respond_with(200, body={
'id': 1,
'username': '张三',
'email': 'zhangsan@example.com'
})
def test_get_user():
with pact:
result = requests.get('http://localhost:1234/api/v1/users/1')
assert result.json()['username'] == '张三'
20.5 契约测试最佳实践
实施步骤
#mermaid-svg-ZnoNoy5o07fYhVOP{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZnoNoy5o07fYhVOP .error-icon{fill:#552222;}#mermaid-svg-ZnoNoy5o07fYhVOP .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZnoNoy5o07fYhVOP .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZnoNoy5o07fYhVOP .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZnoNoy5o07fYhVOP .marker.cross{stroke:#333333;}#mermaid-svg-ZnoNoy5o07fYhVOP svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZnoNoy5o07fYhVOP p{margin:0;}#mermaid-svg-ZnoNoy5o07fYhVOP .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster-label text{fill:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster-label span{color:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster-label span p{background-color:transparent;}#mermaid-svg-ZnoNoy5o07fYhVOP .label text,#mermaid-svg-ZnoNoy5o07fYhVOP span{fill:#333;color:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP .node rect,#mermaid-svg-ZnoNoy5o07fYhVOP .node circle,#mermaid-svg-ZnoNoy5o07fYhVOP .node ellipse,#mermaid-svg-ZnoNoy5o07fYhVOP .node polygon,#mermaid-svg-ZnoNoy5o07fYhVOP .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZnoNoy5o07fYhVOP .rough-node .label text,#mermaid-svg-ZnoNoy5o07fYhVOP .node .label text,#mermaid-svg-ZnoNoy5o07fYhVOP .image-shape .label,#mermaid-svg-ZnoNoy5o07fYhVOP .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZnoNoy5o07fYhVOP .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZnoNoy5o07fYhVOP .rough-node .label,#mermaid-svg-ZnoNoy5o07fYhVOP .node .label,#mermaid-svg-ZnoNoy5o07fYhVOP .image-shape .label,#mermaid-svg-ZnoNoy5o07fYhVOP .icon-shape .label{text-align:center;}#mermaid-svg-ZnoNoy5o07fYhVOP .node.clickable{cursor:pointer;}#mermaid-svg-ZnoNoy5o07fYhVOP .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZnoNoy5o07fYhVOP .arrowheadPath{fill:#333333;}#mermaid-svg-ZnoNoy5o07fYhVOP .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZnoNoy5o07fYhVOP .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZnoNoy5o07fYhVOP .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZnoNoy5o07fYhVOP .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZnoNoy5o07fYhVOP .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZnoNoy5o07fYhVOP .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster text{fill:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP .cluster span{color:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZnoNoy5o07fYhVOP .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZnoNoy5o07fYhVOP rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZnoNoy5o07fYhVOP .icon-shape,#mermaid-svg-ZnoNoy5o07fYhVOP .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZnoNoy5o07fYhVOP .icon-shape p,#mermaid-svg-ZnoNoy5o07fYhVOP .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZnoNoy5o07fYhVOP .icon-shape .label rect,#mermaid-svg-ZnoNoy5o07fYhVOP .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZnoNoy5o07fYhVOP .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZnoNoy5o07fYhVOP .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZnoNoy5o07fYhVOP :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 契约测试实施
定义契约
消费者测试
提供者验证
CI/CD集成
Swagger/Pact
Mock提供者
验证响应格式
自动检查
检查清单
- 接口有Swagger文档
- 消费者测试覆盖所有场景
- 提供者验证通过
- 契约变更通知相关方
- CI/CD中自动运行契约测试
20.6 本章小结
契约测试核心
#mermaid-svg-2EUbzJhkntqLdHDb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-2EUbzJhkntqLdHDb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-2EUbzJhkntqLdHDb .error-icon{fill:#552222;}#mermaid-svg-2EUbzJhkntqLdHDb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-2EUbzJhkntqLdHDb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-2EUbzJhkntqLdHDb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-2EUbzJhkntqLdHDb .marker.cross{stroke:#333333;}#mermaid-svg-2EUbzJhkntqLdHDb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-2EUbzJhkntqLdHDb p{margin:0;}#mermaid-svg-2EUbzJhkntqLdHDb .edge{stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .section--1 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section--1 path,#mermaid-svg-2EUbzJhkntqLdHDb .section--1 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section--1 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section--1 text{fill:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth--1{stroke-width:17;}#mermaid-svg-2EUbzJhkntqLdHDb .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-0 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-0 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-0 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-0 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-0 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-0{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-0{stroke-width:14;}#mermaid-svg-2EUbzJhkntqLdHDb .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-1 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-1 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-1 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-1 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-1 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-1{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-1{stroke-width:11;}#mermaid-svg-2EUbzJhkntqLdHDb .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-2 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-2 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-2 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-2 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-2 text{fill:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-2{stroke-width:8;}#mermaid-svg-2EUbzJhkntqLdHDb .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-3 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-3 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-3 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-3 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-3 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-3{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-3{stroke-width:5;}#mermaid-svg-2EUbzJhkntqLdHDb .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-4 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-4 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-4 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-4 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-4 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-4{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-4{stroke-width:2;}#mermaid-svg-2EUbzJhkntqLdHDb .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-5 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-5 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-5 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-5 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-5 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-5{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-5{stroke-width:-1;}#mermaid-svg-2EUbzJhkntqLdHDb .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-6 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-6 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-6 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-6 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-6 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-6{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-6{stroke-width:-4;}#mermaid-svg-2EUbzJhkntqLdHDb .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-7 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-7 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-7 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-7 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-7 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-7{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-7{stroke-width:-7;}#mermaid-svg-2EUbzJhkntqLdHDb .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-8 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-8 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-8 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-8 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-8 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-8{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-8{stroke-width:-10;}#mermaid-svg-2EUbzJhkntqLdHDb .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-9 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-9 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-9 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-9 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-9 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-9{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-9{stroke-width:-13;}#mermaid-svg-2EUbzJhkntqLdHDb .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-10 rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-10 path,#mermaid-svg-2EUbzJhkntqLdHDb .section-10 circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-10 polygon,#mermaid-svg-2EUbzJhkntqLdHDb .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-10 text{fill:black;}#mermaid-svg-2EUbzJhkntqLdHDb .node-icon-10{font-size:40px;color:black;}#mermaid-svg-2EUbzJhkntqLdHDb .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .edge-depth-10{stroke-width:-16;}#mermaid-svg-2EUbzJhkntqLdHDb .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled,#mermaid-svg-2EUbzJhkntqLdHDb .disabled circle,#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:lightgray;}#mermaid-svg-2EUbzJhkntqLdHDb .disabled text{fill:#efefef;}#mermaid-svg-2EUbzJhkntqLdHDb .section-root rect,#mermaid-svg-2EUbzJhkntqLdHDb .section-root path,#mermaid-svg-2EUbzJhkntqLdHDb .section-root circle,#mermaid-svg-2EUbzJhkntqLdHDb .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-2EUbzJhkntqLdHDb .section-root text{fill:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .section-root span{color:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .section-2 span{color:#ffffff;}#mermaid-svg-2EUbzJhkntqLdHDb .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-2EUbzJhkntqLdHDb .edge{fill:none;}#mermaid-svg-2EUbzJhkntqLdHDb .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-2EUbzJhkntqLdHDb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 契约测试
目的
前后端一致性
早期发现问题
工具
Swagger文档
Pact验证
流程
定义契约
消费者测试
提供者验证
实践
CI/CD集成
变更通知
课后练习 📝
-
实践题:为一个简单接口编写Swagger文档。
-
编程题:用Pact编写一个消费者契约测试。
20.7 下章预告
下一章我们将学习接口测试CI/CD集成!
"契约测试是前后端的'合同',确保双方都按约定行事。"