返回 Web 功能测试简化订单状态图
一条迁移的完整断言
支付成功与超时关单竞争 幂等处理的核心路径
外部成功后的恢复路径
Main Track / Tutorial 07
业务状态流转测试实战教程
把订单看成“当前状态 + 触发操作 + 流转规则”,验证支付、取消和退款在正常、重复、乱序与并发下是否仍然正确。
9 个章节订单支付退款状态流转 + 并发 + 补偿
01
为什么复杂业务要明确状态流转
不只测试页面按钮当前状态决定接下来允许做什么
订单处于“待支付”时可以支付或取消;进入“已支付”后可以履约或退款,却不应回到普通待支付。把当前状态、触发操作和目标状态整理成规则,专业上称为“状态迁移测试”,部分资料也称“状态机测试”。
待支付
支付 → 已支付
取消/超时 → 已关闭
已支付
申请退款 → 退款中
退款中
渠道成功 → 已退款
渠道失败 → 可重试
当前状态
某一时刻可以稳定观察的业务阶段。
触发操作
用户、定时任务或外部回调发起的动作。
流转规则
允许条件、目标状态、数据副作用和失败处理。
02
从需求建立状态模型
先穷举再执行建模步骤
- 找出订单、支付单、退款单三个状态主体。
- 列出每个主体所有可观察状态。
- 标出用户操作、超时任务和渠道回调事件。
- 为每次迁移写前置、目标状态和副作用。
- 补上失败、重复、乱序和人工处理路径。
订单合法迁移表
| 当前状态 | 事件 | 目标状态 | 关键副作用 |
|---|---|---|---|
| 待支付 | 支付成功 | 已支付 | 支付记录成功,库存保持已扣减 |
| 待支付 | 用户取消 | 已取消 | 释放库存,优惠券可恢复 |
| 待支付 | 超时关闭 | 已关闭 | 拒绝后续普通支付 |
| 已支付 | 申请退款 | 退款中 | 创建一笔退款单 |
| 退款中 | 渠道退款成功 | 已退款 | 资金、订单和退款单一致 |
状态名称要能由接口或数据查询证实。“处理中”若没有明确进入和退出条件,就还不是可测试的状态定义。
03
覆盖每一条合法状态迁移
节点与边都要测前置状态待支付
触发事件支付成功
目标状态已支付
业务副作用支付记录与通知
合法迁移用例
- 当待支付订单完成支付时,订单进入已支付且支付记录成功。
- 当待支付订单超过有效期时,订单关闭并释放库存。
- 当已支付订单满足退款条件时,创建退款单并进入退款中。
- 当退款渠道返回成功时,订单进入已退款且金额一致。
每条迁移至少验证
- 事件前状态与权限满足前提。
- 接口返回 HTTP 200 后,业务码说明本次业务是否受理。
- 主体进入唯一目标状态。
- 库存、金额、优惠券和消息副作用正确。
- 页面能够展示最新状态且操作入口同步变化。
04
主动验证非法迁移
不能走的路同样重要非法迁移与预期防线
| 非法迁移 | 触发方式 | 预期 |
|---|---|---|
| 已取消 → 已支付 | 迟到的支付成功回调 | 拒绝直接覆盖;进入异常处理或补偿 |
| 已退款 → 退款中 | 重复点击退款 | 返回原退款结果,不新建退款单 |
| 待支付 → 已退款 | 跳过支付直接改状态 | 拒绝并记录审计 |
| 已支付 → 待支付 | 人工错误回退 | 禁止普通接口逆向迁移 |
执行方式
- 通过测试接口或可控工具准备指定状态。
- 发起在当前状态不允许的事件。
- 确认接口拒绝且返回明确业务原因。
- 核对订单及关联数据完全不变。
- 检查审计日志和告警是否满足设计。
05
制造并发事件和竞争条件
顺序不同,结果仍要守约束事件 A
支付渠道回调成功
事件 B
超时任务尝试关单
唯一终态
按锁、版本或规则只接受一条迁移
关键并发用例
- 当支付成功和超时关闭几乎同时发生时,订单只进入一个合法终态。
- 当用户 A 与客服同时发起退款时,只创建一笔有效退款。
- 当两个设备同时提交最后一件库存时,只允许一笔订单占用成功。
- 当支付回调与用户查询并发时,查询不得展示不存在的中间组合。
并发测试要记录每个请求的发送时间、幂等键、request_id 和最终数据;只看两次页面点击无法证明竞争条件。
06
验证重复提交与幂等
相同意图只产生一次结果首次请求携带幂等键
保存结果状态与响应
重复请求识别相同意图
返回原结果不重复副作用
幂等检查
| 场景 | 操作 | 必须成立 |
|---|---|---|
| 重复下单 | 同一幂等键连续提交 | 只有一个订单,库存只扣一次 |
| 重复支付 | 按钮双击或网络重试 | 只有一笔有效支付 |
| 重复回调 | 渠道发送相同通知 | 状态不二次推进 |
| 重复退款 | 相同退款请求重放 | 金额不累计,返回原退款单 |
07
测试失败回滚与异步补偿
失败后仍能恢复支付已成功外部事实
订单更新失败局部异常
记录待补偿可追踪
重试或人工恢复一致
故障场景
- 当订单创建后库存扣减失败时,订单不进入可支付状态或被可靠关闭。
- 当支付成功但订单更新失败时,补偿任务根据支付事实推进订单。
- 当退款成功但消息发送失败时,可重试消息且不重复退款。
- 当补偿连续失败时,系统告警并进入可人工处理状态。
回滚适合尚未对外生效的本地操作;外部支付已经成功时不能假装回滚资金,必须通过补偿和对账恢复一致。
08
核对跨对象状态与数据一致性
一个订单,多份事实终态一致性断言
| 订单状态 | 支付单 | 退款单 | 库存与优惠券 |
|---|---|---|---|
| 待支付 | 未支付 | 不存在 | 按规则锁定 |
| 已支付 | 成功且金额一致 | 不存在 | 库存已扣,优惠已使用 |
| 已取消/关闭 | 无成功支付 | 不存在 | 库存与优惠已释放 |
| 退款中 | 支付成功 | 处理中 | 按业务约定处理 |
| 已退款 | 支付成功 | 成功且不超实付 | 按规则恢复 |
可执行核对
- 保存订单号、支付单号和退款单号。
- 查询接口返回的当前状态和业务码。
- 核对数据库中的主体版本、金额和更新时间。
- 检查库存、优惠券、消息和账务副作用。
- 在最终一致性时间窗后再次查询。
- 超时仍不一致时保存证据并触发告警。
09
完成一套订单状态流转测试
从规则到证据练习
- 画出待支付、已支付、已取消、退款中和已退款。
- 为每条合法流转写一条“当……时,……”用例。
- 补充四条非法流转并验证数据不变。
- 设计支付与关单、退款与重复回调两个竞争场景。
- 验证下单、支付和退款的幂等键。
- 模拟订单更新失败并检查补偿与告警。
规则完整
- 状态可观察
- 操作已穷举
- 终态明确
- 副作用明确
异常充分
- 非法流转拒绝
- 并发终态唯一
- 重复请求幂等
- 乱序可处理
结果可信
- 多对象一致
- 补偿可验证
- 告警可触发
- 证据可追溯