☰
基于模型的测试(MBT)落地实践:从模型设计到用例生成与执行
2026/10/13 7:11:43 网站建设 项目流程

如果你在测试岗待过几年,大概率经历过这样的场景:接口文档更新了,用例却没跟上;回归包越来越长,真正有价值的覆盖却越来越少;新同学接手老用例,根本不知道当初为什么要写这一步。我一度以为是自己团队的管理问题,直到把视线转向基于模型的测试(MBT),才意识到这是个结构性缺陷——我们在用手工方式维护一套本该由机器生成的资产。

MBT的核心思路不复杂:把“被测系统的行为规则”整理成模型,再由工具从模型自动推演、生成测试用例。它解决的不是“多写一条用例”,而是“用例从哪来、如何保证覆盖、变更后怎么快速重建”这个更上游的问题。

这篇文章里,我会结合自己落地 MBT 的真实经历,把从模型设计、覆盖策略、工具选型到端到端执行的过程完整讲一遍,也会把那些文档里很少写的坑一并摊开。适合正在评估 MBT、或者已经在试点但效果不如预期的团队参考。

1. 从手工用例到模型驱动:我为什么在团队里推 MBT

1.1 什么时候需要 MBT?我观察到的四个信号

很多团队听说“MBT”这个名词时,第一反应是“要不要追新”。我的判断标准一直很朴素:只有当手工用例的维护成本开始倒挂测试价值时,才值得引入模型驱动。下面四个信号如果同时出现三条,基本可以判断团队已经具备试点条件:

第一,用例数量增速失控。业务版本迭代快,测试用例每个月都在叠加,谁也不敢删,因为每条用例背后都对应过一次线上事故或需求变更,“历史资产不能丢”成了删用例的障碍。

第二,覆盖逻辑说不清。测试负责人被问“当前版本覆盖了哪些状态和路径”时,只能给出模糊的百分比,无法精确指出哪些分支没跑到。

第三,回归准备周期长。临近发版,手工整理回归集、标注优先级、补充新用例,往往要占掉一个测试周期里两到三天,纯纯的“准备时间”。

第四,自动化用例相互耦合。脚本里充斥着“先执行某条用例,再执行下一条”的先后依赖,改一个地方倒一片。

我们当时的项目正好符合前三条。核心交易流程有几十个状态节点,分支条件多,线上配置项频繁调整,手工用例从最初的几百条膨胀到两千多条,但每次发版真正被验证过的场景不超过三成。当我把这些数字写进 PPT 时,团队才意识到问题不在“人不够”,而在用例生成模式本身不可持续。

1.2 从“用例为先”到“模型为先”的转变

传统自动化测试的路径是:分析需求 → 编写用例 → 编写脚本 → 执行维护。这个链路有个隐含前提——需求是稳定的、可枚举的。但现实中,业务状态流转一多,路径组合就是指数级的,手工枚举根本跟不上。

MBT 把链路倒了过来:分析需求 → 建模 → 生成用例 → 执行。模型的抽象层级比用例高,它记录的是“系统在什么条件下做什么动作、如何迁移状态”,而不是“第几步点什么按钮”。当需求变化时,修改的粒度从“改几百条用例”缩小到“改模型中的一个转移条件”,然后重新生成整套用例。

这里有个关键认识:模型不是图,而是可执行的行为规格。哪怕你只用状态机图标了几张图,只要它是结构化的、可被工具解析的,就已经比 Word 里的测试点清单前进了一大步。

1.3 角色分工:建模者、开发、QA 如何配合

试点 MBT 不需要招“模型测试专家”,但需要重新定义角色职责。我们当时做了个调整,效果很好:

  • 测试架构师(或资深 QA):承担建模者的角色,负责理解业务规则并表达为状态机/流程模型。
  • 开发工程师:提供接口状态转移的真实约束,尤其是异常分支、超时、兜底逻辑。没有开发参与,模型一定会建得过于理想。
  • 测试执行工程师:把生成的用例接入自动化框架,负责断言层和测试数据准备。

关键原则是:建模者必须能直接对话产品经理。因为很多状态节点隐藏在需求文档的“例外条款”里,只有产品经理能向你澄清“某个校验失败后到底是停留在原状态还是跳到终态”。

2. 建模的核心逻辑:不要一开始就画高阶状态机

2.1 前置动作:把业务规则拆成可验证的行为片段

很多团队第一次建模,都喜欢画一张“全流程大图”,把所有状态和转移都塞进去。结果图复杂到没人能看懂,工具生成的用例数量又爆炸。我建议反向操作:先按业务子域拆成若干小模型,再组合验证。

以我们做过的电商交易流程举例,拆解后的行为片段大致是:

  • 购物车:加购、减购、清空、修改数量
  • 结算:创建订单、支付、取消、超时关闭
  • 库存:锁定、扣减、回滚
  • 订单状态:待支付、已支付、待发货、已发货、已完成、已关闭

每个片段的模型都控制在 10 到 20 个状态以内。模型建的太大,生成器跑出的用例往往冗余,排查问题时你很难定位是哪条路径出了问题。按子域拆分后,生成的用例可以单独跑,也可以组合跑,维护成本和定位成本都低得多。

2.2 状态建模的具体方法与要素

这里以支付状态机为例,说明建模时的基本要素:

要素示例
状态集合待支付、支付中、支付成功、支付失败、订单取消、超时关闭
转移动作发起支付、支付回调、取消订单、定时关单
转移条件支付成功回调、支付超时、用户主动取消
前置守卫订单状态必须是待支付才能发起支付
动作副作用支付成功时扣减库存,失败时释放库存

建模时最容易忽略的是“无效转移”。比如一个已经关闭的订单,理论上不能再发起支付。如果你不把这类“不应发生的事”建模进去,生成器永远不会发现系统某处漏写了校验。模型里不仅要有有效路径,还要有非法路径的约束,这才是 MBT 能发现深层缺陷的价值所在。

2.3 从模型到用例:生成器是怎么工作的

工具生成用例时,通常会基于图遍历算法,按照你指定的覆盖准则,在状态图中搜索从初始状态到终止状态的路径。比如“每条转移至少覆盖一次”,对应的是边覆盖;“每个状态至少到达一次”,对应的是点覆盖。这些准则决定了用例数量和覆盖率上限。

模型本身不需要描述“点击哪个按钮”,它描述的是“某条件下发生某动作导致某状态变化”。至于这条动作在 UI 层怎么操作、在接口层怎么拼参数,是由执行适配层解决的。这一点非常关键:同一个模型可以同时驱动接口测试、UI 测试和契约测试,只是执行适配器不同。

3. 用覆盖率、路径与生成器把控用例数量

3.1 覆盖准则:别一上来就追求“全路径覆盖”

几乎每个刚入手 MBT 的人都会问同一个问题:“覆盖率设多少合适?”我见过有人直接上全路径覆盖,结果状态机稍微复杂一点,生成的用例数是天文数字,根本跑不完。

这里引出一个概念:路径爆炸。举个直观的例子,状态机里有 4 个可循环节点,深度限制为 20,全路径组合就有 4 的 20 次方量级的可能性。所以实际落地必须靠覆盖准则约束。

我用过且推荐的覆盖准则从低到高排序如下:

  1. 状态覆盖(State Coverage):每个状态至少被到达一次。这是最基础的,通常适合冒烟级验证。
  2. 转移覆盖(Transition Coverage):每条边至少被走一次。这是回归测试的底线,能保证每个已知动作都被验证过。
  3. 判定覆盖(Decision Coverage):每个转移的分支条件真假值都至少覆盖一次。适用于有复杂分支逻辑的规则型业务。
  4. 条件组合覆盖(MC/DC 类):关注每个条件的独立性影响。用于安全攸关系统或对错误敏感模块。

我们实际在普通业务项目里,边覆盖 + 关键路径覆盖已经能明显优于手工用例。安全模块或资金相关流程才会启用条件组合覆盖。

3.2 生成参数:让用例量控制在可执行范围

即便选定了覆盖准则,生成器还有一堆参数可以调节:最大路径深度、最大用例数、随机种子、路径重复次数等。我的调试习惯是:

  • 先用状态覆盖生成一批,跑通后看整体链路是否连得上;
  • 再用边覆盖生成回归集,观察用例重复度;
  • 如果用例过多,优先设置“最大路径深度”,限制单个用例的长度,而不是限制总条数;
  • 对关键主链路单独拉一条“必经路径”要求,保证最重要的业务场景无论如何都会被生成进去。

举一个实际数字。某核心订单流程模型共有 23 个状态、42 条转移,采用边覆盖后生成 38 条用例,其中有效用例 35 条,3 条是无效路径(对我们用来做负向验证反而有价值)。这些用例覆盖了原有手工用例体系中 80% 的功能点,但数量只有原来的三分之一。

3.3 从生成器到断言:模型给出的是“输入+操作序列”,断言还得自己写

这里要泼一盆冷水:MBT 不会自动告诉你断言怎么写。它生成的是一条操作序列和预期的状态变化,但“支付成功”是返回 200 还是某个状态码变成 1,需要你在执行适配层手动断言。

我们的经验是:把断言抽象成“状态校验器”。每进入一个新状态,就执行一个对应校验函数,检查页面元素或接口字段是否符合该状态的性质。这样,生成器给出路径后,执行层只需要按状态挂载校验器,不需要每条用例单独写断言逻辑。

4. 工具选型:从开源到商用的实际权衡

4.1 我和团队踩过工具选型的坑

选工具是我踩坑最多的一环。刚开始我们以为“带状态机功能”就算 MBT 工具,结果发现很多工具只是把手工测试用例表格画成了状态图,根本没有自动生成能力,最后生成还得靠人肉推导,等于白干。

真正的 MBT 工具至少要具备两个能力:一是能从模型解析出可遍历的图结构;二是能按照覆盖准则自动生成测试序列。

4.2 市面典型工具的横向对比

下面列几类我实际接触或深入调研过的工具形态,按适用场景区分:

工具形态代表模型表达适合团队主要特点
开源图遍历型GraphWalker 及其衍生项目状态机 / EFSM(扩展有限状态机)有 Java 基础的中小团队灵活、可嵌入代码测试,但需要自己搭建执行层
商用模型测试套件Conformiq Creator需求模型 / UML 类模型对流程规范性要求高的大中型企业自动化程度高、报告完善,但许可证成本不低
业务建模平台型Tricentis 等商业平台过程流 / 规则流有现成自动化平台的团队和既有测试平台集成度高,更适合 UI/端到端场景
自研轻量工具自研脚本图模型自定义 JSON/YAML 图有开发能力的 QA 自动化团队前期投入高,但贴合业务、无外部依赖

我们最终选择开源方案加自研执行适配层,核心原因有两个:一是团队已经有 Java 自动化测试框架,GraphWalker 可以直接以 jar 包方式集成;二是我们业务里有很多信息交互和状态同步逻辑,自研 JSON 图模型反而比通用建模工具的强类型模型更灵活。

4.3 选型时的四个检查清单

如果你也在选型,建议按这个顺序排查:

  1. 支持的模型类型是什么?只支持流程图的不一定支持状态回环,务必拿真实业务场景试跑。
  2. 生成用例的覆盖准则是否可配置?只有默认路径的话,很难应对复杂状态机。
  3. 是否支持生成结果的持久化与关联?用例生成后要被自动化框架识别,最好能和缺陷管理系统挂钩。
  4. 社区活跃度和案例多不多?多数 MBT 工具的学习曲线很陡,遇到问题没有社区解答会很痛苦。

5. 一次完整落地小案例:从模型到执行报告

5.1 场景建模:登录与账户锁定流程

为了让读者能完整走一遍流程,这里我用一个“登录与账户锁定”的场景作为迷你案例。

业务规则如下:

  • 用户可以输入用户名、密码登录;
  • 密码错误时,登录失败,失败计数加一;
  • 连续失败 5 次,账户锁定;
  • 锁定期为 30 分钟,到期后自动解锁;
  • 管理员可以手动解锁;
  • 已锁定状态下,即使密码正确也不能登录。

我把状态定义为:未登录、登录失败(计数为 N)、登录成功、账户锁定。

转移条件如下:

从 未登录 到 登录失败(N):输入错误密码,计数 N+1,若 N+1 < 5 从 登录失败(N) 到 登录失败(N+1):再次输入错误密码,N+1 仍小于 5 从 登录失败(N) 到 账户锁定:当 N+1 = 5 从 未登录 或 登录失败(N) 到 登录成功:输入正确密码且账户未锁定 从 账户锁定 到 未登录:等待 30 分钟超时,或管理员解锁 从 账户锁定 到 登录成功:不存在(非法路径,模型应体现)

模型看起来简单,但生成时会发现模块逻辑中一个有意思的点:尝试密码错误后,系统是否会把旧的失败计数清零?例如连续失败 3 次后,用户通过校验验证码机会成功登录了一次,下一次失败时是从第 1 次重新计数,还是沿用之前的 3 次?这个细节不建模,测试用例永远测不到。

5.2 生成与执行:边覆盖下得到的样例路径

工具按边覆盖生成后,我们拿到了一段典型的用例序列,大致如下:

  1. 未登录 → 输入错误密码 → 登录失败(1) → 输入错误密码 → 登录失败(2) → 输入错误密码 → 登录失败(3) → 输入错误密码 → 登录失败(4) → 输入错误密码 → 账户锁定 → 等待解锁 → 未登录 → 输入正确密码 → 登录成功
  2. 未登录 → 输入正确密码 → 登录成功(验证正常路径)
  3. 登录失败(2) → 输入正确密码 → 登录成功(验证失败后恢复)

执行结果显示:第一条长路径运行到第 4 次输入错误密码时,系统返回的失败计数不是 4,而是 3。最终定位发现,失败计数在每次密码错误后从数据库读取时,出现了并发场景下的脏读——这个缺陷在手工用例里基本不会暴露,因为手工测试通常按顺序输入,很难触发并发读取不一致的场景。

5.3 从案例中得到的可复用经验

这个小案例告诉我们三个可复用的要点:

  • 非法路径必须建模:账户锁定后再输入正确密码,很多业务确实不会校验锁定状态,这种缺陷靠流程类用例很难发酵出来,但 MBT 的图遍历很容易把这条路径拽出来执行。
  • 连续操作类场景用状态机建模很合适:计数、重试、锁定这类有明确状态流转逻辑的场景,是 MBT 最简单的切入点,适合作为团队第一个试点选择。
  • 执行阶段需要配合数据清理:因为用例会反复触发状态变化,每次执行后需要把账户状态重置为“未登录”,否则路径会被锁死。我们在执行适配层统一封装了“测试前重置”逻辑,避免这种问题干扰结果。

6. 落到真实迭代中的三个大坑与我的解决办法

6.1 模型漂移:模型和代码总是会慢慢不一致

真正上线之后,团队面临的第一个大问题是模型漂移。产品在不断迭代,模型在工具里还是旧版,测试人员一旦忘了同步更新,生成的用例就跑在老规则上,造成假绿或假红。

我的解决办法是把模型纳入代码仓库,并在持续集成(CI)流程里增加模型与代码的关联校验。具体而言:

  • 模型文件(JSON/YAML 格式)与源代码一起评审、一起提交;
  • 发起变更时,要求开发在 MR 描述中指明对状态机的影响;
  • 如果状态枚举变了,建模者会收到代码变更事件提醒,必须在两个迭代内更新模型。
  • 在 CI 中跑“模型一致性测试”:从代码里反射出当前状态枚举、动作枚举,和模型文件比对,不一致直接报错。

这样做之后,模型漂移的概率显著下降。虽然不能完全杜绝,但至少不会再出现“跑了半小时用例才发现模型是三个月前”的情况。

6.2 覆盖率没达到预期:别急,先查数据流问题

还有个容易引发争论的坑是:模型建得很完善,但边覆盖就是达不到 90% 以上。排查下来往往不是模型的问题,而是被测系统本身就存在不可达状态。

比如某个状态节点定义了“收到支付回调进入支付成功”,但实际线上支付回调只会在“等待扣款确认”状态下出现,模型里的初始状态到“受邀支付回调”之间的路径是死路。这时候 MBT 反而是个好工具——它帮你发现了业务规则里定义的路径和代码实现不一致。遇到这种情况,我的建议是:

  • 如果不可达路径确实是业务规则冗余,删掉模型里的对应转移;
  • 如果不可达路径是代码缺少入口,这就变成了一个有效缺陷;
  • 不要把“覆盖率没到 100%”一刀切归为生成器不好用。

6.3 自动化回归时间成本:生成容易执行慢

MBT 生成用例很快,但执行层跑完全量回归可能很慢。我们最初全量执行 500 多条生成用例,UI 端到端跑完要 6 个小时,CI 根本等不起。

解法是把用例按执行成本分梯队:

梯队执行范围触发时机
冒烟级状态覆盖,控制 20 条以内每次代码提交后跑
回归级边覆盖 + 关键路径,约百条每天夜间或合并前
全量级边覆盖 + 条件组合,覆盖完整模型发版前或每周一次

分梯队后,日常提交能快速拿到反馈,发版前再跑全量,执行成本和反馈速度取得平衡。

7. 个人复盘:把 MBT 从“工具试用”变成“测试资产”的几个建议

试点 MBT 一年后,我回头总结,这套方法最大的价值其实不是节省了多少工时,而是把测试设计提升到了规格即用例的高度。团队终于不再靠记忆和开会去维护“测试经验”,所有行为规则都沉淀在可解析、可推演的模型里,这对人员流动频繁的测试团队来说是真正的资产沉淀。

如果想在团队里推动 MBT,我建议从一个小而完整的场景切入,最好选择状态流转明显、失败重试多、并发规则复杂的模块。第一波目标不要设成“全面替换手工用例”,而是“在一个模块上用模型生成出足够有说服力的缺陷报告”,用成绩换取团队信任,再逐步扩大范围。

最后提醒一点:MBT 不是银弹。系统中纯展示型、无状态流转的业务,建模收益很低,仍然适合用手工或传统自动化覆盖。把它用在它擅长的地方,它才能发挥最大作用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询