第三章 Mock回放基本原理
这一章我们聊聊最核心的东西——Mock回放究竟是怎么工作的。说白了,就是先录一段真实的网络交互,然后在测试时原样放出来。听起来简单吧?但里面坑不少,我当年刚接触时就被匹配策略坑过好几次。
录制-回放模式
先看两种基本模式:
- 录制模式:启动一个代理,把真实的前台请求和后台响应原封不动地保存下来。
- 回放模式:关闭真实后端,让请求过来时从已录制的数据里找匹配的响应返回。
我常用的一招:先打开录制跑一遍完整的业务流,再切换到回放重复跑。这个过程中,前台的代码完全不需要改——只需要改个配置开关,连启动命令都不用变。
💡 小窍门:录制时最好把重要的请求记录成“黄金数据集”。我习惯每次发版前重新录一遍,保证数据是最新的。
HTTP请求/响应捕获
捕获的本质就是中间人代理。咱们看看它抓住了什么:
| 捕获内容 | 说明 | 常见坑 |
|---|---|---|
| 请求方法 + URL | GET /api/user/profile | URL里的动态参数容易导致匹配失败 |
| 请求头 | Cookie、Authorization等 | 过期后回放可能不匹配 |
| 请求体 | JSON / Form / 二进制 | 大文件或流式请求要特殊处理 |
| 响应状态码 | 200 / 404 / 500 | 注意状态码也要匹配 |
| 响应头 + 响应体 | Content-Type, 实际返回数据 | Content-Encoding如果是gzip,存储时需解压 |
曾经有个项目,前端一直报跨域错,查了半天发现录制时响应头里没存Access-Control-Allow-Origin,回放时浏览器给拦截了。从此我再也不敢省略响应头。
匹配策略
匹配是回放的心脏。策略不对,要么死活找不到匹配,要么错配数据导致测试失败。
精确匹配
最简单粗暴:请求的所有关键字段必须完全一致。包括URL参数顺序、请求体里的空格。我在项目里遇到过因为JSON里多了一个换行符导致匹配失败的,排查到凌晨两点。
模糊匹配
允许用通配符或正则匹配动态部分。比如时间戳、随机数、会话ID。我现在做匹配配置时,会给每个动态字段加一个{ignore}标记,省心很多。
⚠️ 注意:模糊匹配容易造成误匹配。我曾经有一回把/trade/order/123误配给了/trade/order/456,导致测试断言全乱套。后来我强制要求匹配时至少锁定method和URL路径,再配合模糊参数。
优先级与回退
多匹配器并存时,一般按精确->模糊->默认响应的顺序查找。我习惯给每个接口配一个“兜底响应”,避免匹配不到直接抛异常。
// 伪代码示意:匹配优先队列
matchingPipeline:
- type: exact
- type: regex
pattern: "/api/v\d+/orders/(\\d+)"
- type: fallback
responseFile: "default_ok.json"
数据存储模型
录下来的数据怎么放?常见有三种模型:
| 模型 | 特点 | 适用场景 |
|---|---|---|
| 文件树 | 每个请求一个YAML/JSON文件,按目录组织 | 小项目,手动维护 |
| 数据库表 | 用SQLite或内存DB存储请求体与响应体 | 中等规模,支持索引查询 |
| 键值对映射 | 用请求指纹(如SHA256)做key,响应做value | 高性能,适合大量录制数据 |
我个人比较偏爱键值对模型。原因很简单:查找快,还能支持增量录制。不过注意指纹碰撞——我曾在Key里加入URL和method,但忽略了请求体顺序,导致两个请求被当成一个。
存储最佳实践:每个录制条目至少包含:
request.key:由method + URL + 请求头摘要组成request.bodyHash:请求体哈希,用于区分POST请求response.status、response.headers、response.bodymetadata.createdAt:录制时间,方便过期清理
嗯,这张图能帮你快速把握整体流程:
最后说说数据存储里的一个细节:索引结构。我用的模型大致长这样:
{
"fingerprint": "GET:/api/user:hash1234",
"request": {
"method": "GET",
"path": "/api/user",
"query": "id=42",
"headers": {"Authorization": "Bearer ***"},
"body": null
},
"response": {
"status": 200,
"headers": {"Content-Type": "application/json"},
"body": "{\"name\":\"Alice\"}"
},
"meta": {
"recordedAt": "2025-02-18T10:00:00Z",
"ttl": 86400
}
}
曾经我犯过一个错:忘了给录制数据加过期时间,结果压测时回放了三个月前的老数据,接口完全变了。后来我强制每个录制条目都带ttl字段,超时就自动重录。嗯,这些细节积累下来,能让你的Mock回放真正靠谱起来。