AI图鉴

AI图鉴首页 › AI 资讯 › 夯爆了!分享几个我在用的,基于业务场景接口串联测试Skill !

夯爆了!分享几个我在用的,基于业务场景接口串联测试Skill !

来源:掘金 · 发布时间:10-27 · 由 AI图鉴每小时自动聚合

在AI赋能自动化测试全流程,前面分享的系列文章中,我们把接口自动化测试的智能化流水线完整跑通了。 007 篇批量生成了 59 个接口、2000 多条测试数据、159 个测试脚本...

在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 个业务模块:

请确保后端服务已正常启动,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)

质量红线(脚本校验 + 人工复核)

- 接口真实性:编排中每个 api 均存在于 api_definitions.json,绝不虚构接口,缺失环节标记"接口缺失"

- 变量闭环:每个 ${} 引用的变量必有来源,无孤儿变量

- 顺序合法、断言覆盖、幂等保障、无动态字段全等断言

实操演示

1、输入一段自然语言场景描述 + 接口定义文件:

请调用 api-scenario-modeler 技能,基于接口定义文件 /Users/xxx/output/api_definitions.json,

为下述业务场景生成串联编排文件:

新用户注册并登录后,搜索一件商品,查看商品详情,加入购物车,创建订单并完成支付,

最后确认订单状态已流转、库存扣减数量正确。业务规则:已支付订单不可取消。

建模完成后,同时输出 modeling_notes.md。

拿到编排文件和建模说明后,逐项过这张人工评审清单(modeler 的自检清单是 AI 自查,这一步是人查,两道关都要过):

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/

本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。

相关 AI 工具

相关免费羊毛

同源资讯

阅读原文(juejin.cn)

标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。

← 返回 AI 资讯列表AI工具图鉴首页

返回 AI图鉴首页 · 提交工具 · 商务合作 · 关于本站 · 592 款 AI 工具分类导航 · 每日 AI 热门项目与动态