基于业务场景的接口串联测试 Skill:api-scenario-modeler 场景建模实战
夯爆了!分享几个我在用的,基于业务场景接口串联测试Skill ! - 狂师
针对单接口测试无法覆盖业务链路的问题,教程推出 api-scenario-modeler Skill,把自然语言业务场景翻译成标准化的 scenario_*.yaml 编排文件和 modeling_notes.md 建模说明,作为 api-scenario-runner 执行引擎的输入。

在AI赋能自动化测试全流程,前面分享的系列文章中,我们把接口自动化测试的智能化流水线完整跑通了。
- 007 篇批量生成了 59 个接口、2000 多条测试数据、159 个测试脚本。
- 009 篇让这套脚本实现了智能执行、失败自愈与自动报告,P0 级用例通过率最终稳定在 98% 以上。
但如果你停下来,仔细看一眼这套用例库,会发现一个问题:所有用例,测的都是"单接口"。
test_login_success验证的是登录接口本身,test_add_to_cart_boundary验证的是加购接口的参数边界,test_create_order_normal验证的是下单接口的正常返回。
它们彼此之间,没有任何关系——登录用例自己造账号,下单用例自己造订单号,谁也不认识谁。
这带来一个非常典型、也非常危险的场景:
登录接口返回 200,加购接口返回 200,下单接口也返回 200——单接口用例全绿。但用户在页面上发现,下单成功后订单状态一直卡在"待支付",库存也有扣减。你回头去查单接口用例,每一条都是通过的。
问题出在哪?出在接口与接口的衔接处:token 没有正确传递、订单状态机流转卡死、库存扣减与订单创建的数据不一致。这类缺陷,任何一条单接口用例都拦不住。
单接口测试回答的是"这个接口自身对不对",而用户真正关心的是"这条业务流程通不通"。用户用你的产品,从来不只是为了单纯"调用接口",用户真正用的是业务流程。
本篇教程,我们就来补上这块拼图——基于业务场景的接口串联编排测试:把"注册 → 登录 → 搜索 → 加购 → 下单 → 支付 → 查单"这样一条真实业务链路,作为一个完整的测试对象,让前面篇章里那些孤立的单接口,按照业务逻辑串起来跑。
基于业务场景的接口串联编排测试
单接口测试能解决了什么,不能解决什么?
先客观地回顾一下,前面建立起来的利用AI赋能单接口测试体系,到底解决了什么。
站在单个接口的视角,这套体系已经做得相当完整:
api-schema-parser把 接口的定义结构化api-testdata-generator为每个接口构造了正向、边界、异常、安全四个维度的测试数据api-testscript-generator按"接口层 / 用例层 / 数据层"分层规范批量生成了脚本,api-test-optimizer又从 10 个维度做了场景补齐。参数校验、必填项校验、边界极值、非法格式、SQL 注入、无鉴权访问……这些"接口自身作为独立服务单元"的质量问题,都被覆盖到了。
这对应的是测试分层里经典的"点"——每个接口作为一个独立的契约,验证它的输入输出是否符合定义。
但接口自动化测试的完整版图,是"点、线、面"三层:
| 层次 | 测试对象 | 回答的问题 | 前面篇章覆盖情况 |
|---|---|---|---|
| 点(单接口) | 一个接口 | 这个接口自身的契约对不对? | ✅ 已完整覆盖 |
| 线(业务链路) | 一串有依赖关系的接口 | 这条业务流程跑不跑得通? | ⚠️ 仅浅覆盖 |
| 面(跨模块一致性) | 多条链路共享的数据与状态 | 数据和状态在系统里是否一致? | ❌ 基本空白 |
"线"和"面"的空白,具体表现为四类单接口测试天然测不到的缺陷:
- 数据传递缺陷:上游接口的产出(token、商品 ID、订单号、购物车项 ID)没有被下游接口正确消费。单接口测试里这些值都是各自 mock 或围绕接口自身构造的,传递链路从未被真实走过。
- 状态流转缺陷:订单状态机(待支付 → 已支付 → 已发货 → 已完成)、库存锁定与扣减、优惠券核销——状态在多个接口之间流转,,即便单接口全部正常,但任何一环卡死,用户使用时还是会报障。
- 数据一致性缺陷:下单后,订单表、库存表、购物车表三处数据要同步变化。单接口断言只看当前接口的响应,看不见别处的数据。
- 业务规则联动缺陷:比如"库存不足时禁止下单"“未支付订单 30 分钟自动取消",规则本身横跨多个接口和后台任务。
为什么说业务场景测试才是接口自动化测试的重点
这个问题,可以从三个角度来看。
第一个角度,是缺陷的价值分布。
单接口测试拦住的,多是参数校验类的低层级缺陷——这类缺陷开发自测阶段大多能发现,漏到测试环节,修复成本也低。而真正会造成资损、客诉、线上事故的,是流程类缺陷:订单状态卡死、重复支付、库存超卖、优惠叠加计算错误。
这类缺陷藏在接口的衔接处和状态的流转处,只有把链路串起来跑,才暴露得出来。缺陷越靠近业务流程,单接口测试越无能为力,而它的危害恰恰越大。
第二个角度,是回归测试的效率。
版本迭代时,测试团队最先要保住的是什么?是核心业务链路。
一条"登录 → 加购 → 下单 → 支付"的场景用例,一次执行就完成了十几个接口的业务级回归,直接回答了"这个版本核心流程还能不能用"。但相比之下,跑 200 条彼此独立的单接口用例,也无法给出这个结论——因为它们加起来不构成一条流程。
这就是为什么很多团队的接口自动化跑了很多年,开发和产品还是会在发版前问一句"主流程过了没"——单接口通过率回答不了这个问题,业务场景测试才能。
第三个角度,是企业落地的现状与认知。
一个略显扎心的现实是:大量团队的接口自动化,就止步于单接口。用例数量很可观,报告很好看,但业务价值感知度低,开发不信任、老板不买账,久而久之自动化就成了"为了跑而跑"。
反过来,无论是在企业内部推动自动化建设,还是在求职面试中,"接口自动化怎么覆盖业务闭环""跨接口数据依赖怎么处理"都是最高频的问题之一。
能不能把业务场景串联测试做起来,很大程度上决定了一套接口自动化体系是"数量可观"还是"价值可信"。
打个比方:单接口测试是自动化体系的"砖",每一块都方正合格;业务场景测试才是"楼"——用户住的是楼,不是砖。没有砖盖不了楼,但只验砖、不验楼,交付的就是一堆合格的砖。
实战项目准备
本篇教程的实战案例,依旧延续 shop-lab 全栈电商项目。如果你尚未在本地搭建该项目,请参考 007 篇 1.6 章节 完成环境初始化。
本篇的业务场景链路,会横跨项目的 5 个业务模块:
| 模块 | 链路中承担的角色 |
|---|---|
| auth(认证) | 注册、登录,产出全程要用的 token |
| search(搜索) | 找到目标商品,产出 productId |
| product(商品) | 查看详情,获取库存基线 stockBefore |
| cart(购物车) | 加购,产出 cartItemId |
| order(订单) | 下单、支付、查单,是断言的主战场 |
请确保后端服务已正常启动,Swagger UI 可访问:http://localhost:8080/swagger-ui.html,

并且 007 篇生成的 api_definitions.json 接口定义文件还在(本篇场景建模的核心输入之一;如果丢了,用 api-schema-parser 重新解析一遍 /v3/api-docs 即可)。
业务场景接口编排测试Skill
为了实现基于业务场景接口编排测试,我们新开发了两个Skill。
🔹 api-scenario-modeler(场景建模)
🔹 api-scenario-runner(链路执行引擎)
两个 Skill 一个管「测什么」,一个管「怎么跑」,和前面篇章的执行、诊断、清理、报告技能无缝衔接,单接口和业务场景两条线从此在同一个体系里跑。
这篇先来拆解一下api-scenario-modeler(场景建模)第一个Skill。
api-scenario-modeler 介绍
把自然语言描述的业务场景翻译成标准化的 scenario_<场景名>.yaml 场景编排文件 + modeling_notes.md 建模说明,作为下游执行引擎 api-scenario-runner 的直接输入。
核心定位是"场景执行链路的翻译环节",只做一件事:把业务场景翻译成编排文件。
适用场景
- 把业务流程翻译成接口用例(注册→登录→搜索→加购→下单→支付类端到端链路)
- 生成场景 yaml、做场景建模、编排一条接口链路
- 提供了业务场景描述 + api_definitions.json,需要产出可执行的编排文件
使用方式
在 Claude Code 中提供业务场景描述与 api_definitions.json,或输入:
/api-scenario-modeler
建模工作流(8 步)

核心推导规则(R1~R7)
| 规则 | 说明 |
|---|---|
| R1 鉴权前置 | 登录类步骤在前,token 由登录响应提取,后续步骤由 runner 统一注入 |
| R2 数据依赖定向 | 参数依赖谁产出,就排在谁后面(排序唯一依据) |
| R3 禁止硬编码动态值 | ID/token/单号一律 extract 注入,不写死 |
| R4 幂等策略 | 唯一性字段(用户名/手机号/邮箱)用 timestamp/uuid 动态生成 |
| R5 断言分级 | 每步状态码+业务码;关键业务步骤追加字段断言;禁断动态字段全等 |
| R6 终态校验 | 数据变更链路必须设计 db_asserts 终态一致性断言 |
| R7 失败策略 | happy path 用 abort,异常分支验证用 continue 并断言错误码 |
质量红线(脚本校验 + 人工复核)
- 接口真实性:编排中每个 api 均存在于 api_definitions.json,绝不虚构接口,缺失环节标记"接口缺失"
- 变量闭环:每个
${}引用的变量必有来源,无孤儿变量 - 顺序合法、断言覆盖、幂等保障、无动态字段全等断言
实操演示
1、输入一段自然语言场景描述 + 接口定义文件:
请调用 api-scenario-modeler 技能,基于接口定义文件 /Users/xxx/output/api_definitions.json,
为下述业务场景生成串联编排文件:
新用户注册并登录后,搜索一件商品,查看商品详情,加入购物车,创建订单并完成支付,
最后确认订单状态已流转、库存扣减数量正确。业务规则:已支付订单不可取消。
建模完成后,同时输出 modeling_notes.md。



拿到编排文件和建模说明后,逐项过这张人工评审清单(modeler 的自检清单是 AI 自查,这一步是人查,两道关都要过):
| 评审项 | 检查方法 | 合格标准 |
|---|---|---|
| 接口真实性 | 对照 api_definitions.json 逐个核对 api 字段 | 零虚构 |
| 步骤顺序 | 重点看注册→登录、加购→下单、下单→支付的先后 | 数据依赖全部先产出后使用 |
| 变量闭环 | 对照变量流转图,逐个 ${var} 找来源 | 无孤儿变量、无硬编码动态值 |
| 断言分级 | 看下单、支付步骤是否有业务字段断言(订单状态流转) | 关键步骤三级断言齐全 |
| 幂等设计 | 看 username 是否用了 timestamp 策略 | 唯一性字段全部动态化 |
| 存疑点 | 看 modeling_notes.md 是否标记了 addressId 这类前置数据 | 存疑点如实暴露,而非沉默假设 |

scenario_shopping_flow.yaml 业务场景排编文件详细示例(也称之为业务场景测试建模文件)
scenario:
id: SC-order-001
name: 新用户购物主链路(下单支付与库存终态校验)
description: 新用户注册登录后搜索商品、查看详情、加购、下单并支付,校验订单状态流转为已支付、库存扣减恰好等于下单数量,且已支付订单不可取消
priority: P0
tags: [smoke, module:order, scene:business-flow]
variables:
- { name: username, strategy: timestamp, prefix: shop_ }
- { name: phone, strategy: random, prefix: "138" }
- { name: password, value: Test@123456 }
steps:
- step: 1
name: 注册新用户
api: POST /api/auth/register
auth: false
request:
body:
username: ${username}
password: ${password}
email: ${username}@qq.com
phone: ${phone}
extract: []
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
on_failure: abort
- step: 2
name: 用户登录获取令牌
api: POST /api/auth/login
auth: false
request:
body:
username: ${username}
password: ${password}
extract:
- { var: token, from: $.data.token }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.token, op: not_null }
on_failure: abort
- step: 3
name: 搜索目标商品
api: GET /api/search
auth: false
request:
query:
keyword: 手机
page: 1
size: 10
extract:
- { var: productId, from: "$.data.records[0].id" }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.records, op: not_empty }
on_failure: abort
- step: 4
name: 查看商品详情获取库存基线
api: GET /api/product/detail/{id}
auth: false
request:
path: { id: "${productId}" }
extract:
- { var: stockBefore, from: $.data.stock }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.stock, op: not_null }
on_failure: abort
- step: 5
name: 新增收货地址
api: POST /api/address
auth: true
request:
body:
name: 自动化测试收件人
phone: ${phone}
province: 上海市
city: 上海市
district: 浦东新区
detailAddress: 张江高科纳贤路800号
extract:
- { var: addressId, from: $.data.id }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.id, op: not_null }
on_failure: abort
- step: 6
name: 加入购物车
api: POST /api/cart
auth: true
request:
body:
productId: ${productId}
quantity: 1
extract:
- { var: cartItemId, from: $.data.id }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.id, op: not_null }
on_failure: abort
- step: 7
name: 创建订单
api: POST /api/order
auth: true
request:
body:
addressId: ${addressId}
paymentType: 1
cartIds: ["${cartItemId}"]
extract:
- { var: orderId, from: $.data.id }
- { var: orderNo, from: $.data.orderNo }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.orderNo, op: not_null }
- { type: jsonpath, path: $.data.status, op: equals, value: 10 }
on_failure: abort
- step: 8
name: 支付订单
api: POST /api/order/no/{orderNo}/pay
auth: true
request:
path: { orderNo: "${orderNo}" }
body:
payMethod: 1
extract: []
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
on_failure: abort
- step: 9
name: 查询订单确认状态已流转
api: GET /api/order/{id}
auth: true
request:
path: { id: "${orderId}" }
extract:
- { var: orderStatus, from: $.data.status }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.status, op: equals, value: 20 }
- { type: jsonpath, path: $.data.orderNo, op: equals, value: "${orderNo}" }
on_failure: abort
- step: 10
name: 取消已支付订单(预期被拒绝)
api: POST /api/order/{id}/cancel
auth: true
request:
path: { id: "${orderId}" }
extract: []
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: not_equals, value: 0 }
on_failure: continue
- step: 11
name: 复查订单状态未被取消影响
api: GET /api/order/{id}
auth: true
request:
path: { id: "${orderId}" }
extract: []
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.status, op: equals, value: 20 }
on_failure: abort
- step: 12
name: 复查商品详情获取库存终态
api: GET /api/product/detail/{id}
auth: false
request:
path: { id: "${productId}" }
extract:
- { var: stockAfter, from: $.data.stock }
assert:
- { type: status_code, value: 200 }
- { type: jsonpath, path: $.code, op: equals, value: 0 }
- { type: jsonpath, path: $.data.stock, op: not_null }
on_failure: abort
postconditions:
db_asserts:
- { name: 订单终态为已支付, sql: "SELECT status FROM t_order WHERE order_no = '${orderNo}'", expect_value: 20 }
- { name: 库存扣减与下单数量一致, sql: "SELECT stock FROM t_product WHERE id = ${productId}", expect_expr: "${stockBefore} - 1" }
- { name: API库存与DB库存一致, sql: "SELECT stock FROM t_product WHERE id = ${productId}", expect_expr: "${stockAfter}" }
- { name: API订单状态与DB一致, sql: "SELECT status FROM t_order WHERE order_no = '${orderNo}'", expect_expr: "${orderStatus}" }
cleanup:
- { name: 回收测试用户与订单数据, via: api-testdata-cleaner, scope: ["user:${username}", "order:${orderNo}"] }
并且还会生成一份建模说明文件:modeling_notes.md,每个步骤对应的选择接口,以及选择理由。

各接口之间变量流转图(从变量名->来源定义->注入点)

还会基于业务场景自动生成一份存疑点点清单,这里的存疑点,意味着AI不太明确或者没有把握的地方,这个部分人工需要重点确认。

自检结果:

如何获取Skill
所有实战演练创建生成的 skill,会统一上传到 GitHub中,学员可按需自取。

同时,目前所有 Skill 均已统一上传至网站 testfather.cn Skill 技能商店中。

本篇新增的两个 Skill,安装方式与之前一致,将 Skill 目录复制或克隆到你的 Claude Code 或 WorkBuddy 技能目录下即可使用:
## 在线安装
npx skills add xxx/api-scenario-modeler
npx skills add xxx/api-scenario-runner
# 克隆仓库
git clone git@github.com:xxx/skills.git
# 复制到 Claude Code 技能目录
cp -r skills/api-scenario-modeler ~/.claude/skills/
cp -r skills/api-scenario-runner ~/.claude/skills/
# 或复制到 WorkBuddy 技能目录
cp -r skills/api-scenario-modeler /Users/xxx/.workbuddy/skills/
cp -r skills/api-scenario-runner /Users/xxx/.workbuddy/skills/
来源:博客园 · cnblogs.com