第4章 等价类划分法(下):复杂场景等价类划分与组合情况处理
上一讲我们聊了基础等价类划分,把单输入、单条件的用例设计讲透了。但实际工作中,你不可能只测一个参数。两个、三个甚至更多输入组合在一起,等价类怎么玩?这堂课我就把复杂场景下的等价类划分讲明白。
说白了,复杂场景的核心就是两个问题:多个输入条件怎么划分?组合爆炸怎么控制?我当年刚入行时吃过这亏——给一个订单系统写用例,把每个输入字段的等价类都列出来,然后全排列,结果写出了300多条用例,项目经理差点没把我当桌面清理掉。
多输入参数的等价类组合原则
多个参数组合时,有个基本原则我一直在用:先独立划分,再识别依赖。什么意思?每个参数先按单输入规则找出自己的有效等价类和无效等价类;然后看参数之间有没有耦合关系。如果有依赖,就按依赖情况合并;如果完全独立,就做正交组合或边界组合。
我的经验:80%的缺陷都发生在「边界值交叉」或「依赖条件违反」的地方。与其全组合,不如先识别哪些参数之间有业务约束。比如日期范围的「开始日期」和「结束日期」,明显有「开始<结束」的依赖,这就是等价类合并的关键点。
实战:用户注册表单的复杂等价类划分
来看一个我亲自做过的案例。一个用户注册接口,有三个必填字段:
- 用户名:长度6-20个字符,只能包含字母和数字
- 年龄:18-60岁整数
- 邮箱:标准邮箱格式,且只能使用 qq.com、163.com 或 gmail.com 域名
这三个参数之间有没有依赖?仔细分析:没有。用户名和年龄无关,邮箱和用户名无关。那么就可以用 Pairwise(成对组合) 策略来减少用例数量。但为了讲清楚,我先列一下每个参数的等价类:
| 参数 | 有效等价类 | 无效等价类(示例) |
|---|---|---|
| 用户名 | 6-20位字母数字组合(如 "user123456") | 长度<6、长度>20、含特殊字符、含中文 |
| 年龄 | 18-60整数(如 25) | <18、>60、非整数、空值 |
| 邮箱 | 合法邮箱且域名属于白名单(如 test@qq.com) | 格式不对、域名不在列表中、空值 |
如果做全排列,有效类有 1×1×1=1种(最正常情况),但无效类有 (3+4+3)=10种?不对,实际上是每个参数可以取任意无效类,组合起来爆炸。为了覆盖所有单参数无效和边界,我一般用单缺陷假设:每次只让一个参数取无效值/边界值,其他参数都用有效值。这样组合量就从指数的级别降到了线性级别。
比如年龄的边界测试:
- 年龄 = 17(无效,小于下边界)
- 年龄 = 18(有效,下边界)
- 年龄 = 60(有效,上边界)
- 年龄 = 61(无效,大于上边界)
- 年龄 = 25.5(无效,非整数)
其他字段保持有效值。用户名和邮箱同理。这样总共用例数 = (用户名边界+年龄边界+邮箱边界) + 几个典型全有效组合。我遇到过不少团队非要全组合,结果测了一堆重复场景,核心边界反而漏了。
核心结论:多参数组合时,优先用「单缺陷假设+边界值覆盖」。如果业务要求必须覆盖多个参数同时无效的场景(比如双输入错误),再用Pairwise工具或正交表。别自己数组合,会数到怀疑人生。
依赖参数的等价类合并
有些参数之间有明确约束。比如「支付方式」和「支付金额」。微信支付单笔限额5万,银行卡支付单笔限额10万。这两个参数就不能独立划分了——你得把两个等价类「绑定」起来。
我建议的方法:先画出参数依赖关系图。比如:
- 如果支付方式 = 微信,则金额等价类为:[0.01, 50000]有效,(50000, +∞)无效
- 如果支付方式 = 银行卡,则金额等价类为:[0.01, 100000]有效,(100000, +∞)无效
合并后,最终的等价类划分变为:
| 支付方式 | 金额有效等价类 | 金额无效等价类 |
|---|---|---|
| 微信 | 0.01 – 50000 | >50000 |
| 银行卡 | 0.01 – 100000 | >100000 |
然后把每个分支的边界值分别测一遍。比如微信侧:测0.01、50000、50000.01;银行卡侧:测0.01、100000、100000.01。这样一来,依赖关系被完整覆盖,用例数不会膨胀。
我踩过的坑:曾经有一个运费计算模块,重量和地区有依赖关系(某些地区按体积重计费),我图省事把两个等价类独立划分了。结果线上出现了「地区A+轻量高体积」的订单费计算错误。从那以后,只要参数有依赖,我一定先画依赖表再分等价类。
等价类组合的因果图思维
如果参数依赖关系比较复杂(比如三个以上条件互相制约),我建议用简化的因果图来梳理。不必真画成因果图那么累,就画个逻辑表格:
- 条件1(真/假)→ 动作A
- 条件1为真且条件2为真 → 动作B
- 条件1为假且条件2为真 → 动作C
你想想看,这就是等价类组合的逻辑判断。在测试设计时,把这些逻辑分支作为不同的等价类场景即可。
举个例子:一个借款产品的审批规则。
- 用户等级为VIP 且 借款金额≤5000 → 自动通过
- 用户等级为VIP 且 借款金额>5000 → 人工审核
- 用户等级为普通 且 借款金额≤2000 → 自动通过
- 用户等级为普通 且 借款金额>2000 → 拒绝
这里「用户等级」和「借款金额」两个参数有组合逻辑依赖。等价类划分:
| 组合编号 | 用户等级 | 金额范围 | 预期结果 |
|---|---|---|---|
| 1 | VIP | ≤5000(有效) | 自动通过 |
| 2 | VIP | >5000(有效) | 人工审核 |
| 3 | 普通 | ≤2000(有效) | 自动通过 |
| 4 | 普通 | >2000(有效) | 拒绝 |
再把每个边界值(2000, 5000, 2001, 5001)补上,用例就清晰了。
关键手法:对逻辑组合场景,用「决策表」的方式枚举所有条件组合,再合并等价的组合。通常组合数不会超过 2^n(n为条件数),n=4时16种组合,手动可处理。如果n>5,就得用工具。
控制组合爆炸的实用策略
我总结了三种策略,按优先级排序:
- 单缺陷假设:每次只改变一个参数的值,其他参数用典型有效值。覆盖所有无效类和边界值后,用例数 = (每个参数的无效类个数之和 + 边界点数之和) + 1条全有效用例。
- Pairwise成对组合:如果参数较多(比如4-6个),但参数间没有明显依赖,用Pairwise确保每两个参数的所有取值组合都被覆盖到。工具如PICT或AllPairs都可以,几分钟生成几十条用例。
- 正交表:参数取值个数相同时用正交表效率最高。比如3个参数,每个有2个取值,用L4正交表只需4条用例。但注意正交表不能保证覆盖所有边界,需要额外补充边界测试。
我个人最喜欢「单缺陷假设+边界值补充」。简单、易理解、易评审,而且发现缺陷的能力不差。我曾经把一个有7个输入参数的接口用这个方法压缩到了23条用例,上线后只漏了一个极端并发场景,而那个场景用Pairwise也覆盖不到。所以不存在银弹,视业务复杂度选策略。
总结一下这章的核心心法
复杂场景等价类划分,其实就三步:
- 拆参数:每个参数独立划分出有效、无效、边界等价类;
- 看依赖:识别参数间的业务约束,有依赖的合并为绑定等价类,无依赖的保持独立;
- 选策略:根据参数个数和依赖复杂度,选择单缺陷假设、Pairwise或正交表,然后补边界值。
记住:等价类划分不是为了把所有组合都测一遍,而是用最少的用例覆盖最可能出错的区域。边界和依赖才是重灾区。我自己复盘过多次线上故障,至少七成是边界或依赖逻辑写错了。你想想看,花心思把这两块覆盖好,比堆用例数划算得多。