3、测试用例设计方法(上):等价类划分法、边界值分析法、因果图法

大家好,我是老张。今天咱们聊聊测试用例设计。说实话,这可能是整个黑盒测试里最核心的功夫了。

你想想看,一个系统有成百上千个输入。你不可能把所有组合都测一遍。那怎么办?就得靠方法。我这些年带团队,发现很多新人上来就凭感觉写用例。结果呢?要么漏测,要么重复。今天我把三个最基础、也最实用的方法掰开揉碎了讲给你听。

3.1 等价类划分法:把无穷变成有限

等价类划分,说白了就是「分堆」。把输入数据分成几个类别。每个类别里,挑一个代表测就行了。

为什么能这么干?因为程序处理同类数据的方式是一样的。你测了1号,2号、3号就不用测了。这叫「等效」。

3.1.1 有效等价类 vs 无效等价类

这里有个关键点:一定要分两种。

  • 有效等价类:符合需求、程序应该正常处理的输入
  • 无效等价类:不符合需求、程序应该拒绝或报错的输入

我在项目中遇到过一件事。有个同事只测了有效数据。结果上线后,用户输入了一个负数,系统直接崩溃了。嗯,这就是典型的无效等价类没覆盖到。

核心原则:每个无效等价类,要单独设计一个测试用例。因为程序处理不同错误的方式可能不一样。你把它放一起测,可能第一个错误就挡住了后面的。

3.1.2 划分原则

怎么分?我一般按这几个维度来:

  1. 数值范围:比如年龄 0-150,可以分成 0-150(有效)、<0(无效)、>150(无效)
  2. 枚举值:比如性别「男、女」,有效就是这两个,无效就是其他所有
  3. 布尔值:true 和 false,各算一个
  4. 字符串长度:比如密码 6-16 位,有效是 6-16,无效是 <6 和 >16
  5. 格式规则:比如邮箱必须包含 @,有效是带 @ 的,无效是不带的

3.1.3 实战案例:用户注册模块

咱们拿一个注册功能练练手。需求是这样的:

  • 用户名:6-12位字母或数字
  • 密码:8-16位,必须包含字母和数字
  • 年龄:18-60岁整数

我一般会画个表:

输入项 有效等价类 无效等价类
用户名 6-12位字母数字组合 <6位、>12位、含特殊字符、含中文
密码 8-16位,含字母和数字 <8位、>16位、纯字母、纯数字、含特殊字符
年龄 18-60整数 <18、>60、小数、非数字

你看,原来可能有几万种组合。现在呢?有效类3个,无效类加起来10个左右。13个用例就搞定了。

我的习惯:先列有效等价类,再列无效等价类。无效的每个都要单独测。别偷懒,我吃过亏。

3.2 边界值分析法:bug 最喜欢藏在边界上

等价类划分有个弱点。它假设同类数据表现一致。但现实不是这样的。程序在边界处最容易出问题。

为什么会这样?因为程序员写代码时,经常用 <=<。差一个等号,结果天差地别。边界值分析法就是专门抓这种 bug 的。

3.2.1 边界值的基本概念

对于一个范围 [1, 100],边界值包括:

  • 上点:1 和 100(边界上的点)
  • 离点:0 和 101(边界附近最近的点)
  • 内点:50(范围内的任意点)

我一般习惯取「最小值、最小值-1、最小值+1、最大值、最大值-1、最大值+1」。一共6个值。

3.2.2 边界值 vs 等价类:怎么配合?

这两个方法不是二选一,是搭档。我通常的做法是:

  1. 先用等价类划分,确定大类
  2. 再对每个边界,用边界值分析法补充用例

举个例子。年龄 18-60:

  • 等价类:有效(18-60)、无效(<18、>60)
  • 边界值:17、18、19、59、60、61

你看,边界值把等价类的边界挖得更细了。

注意:边界值不只适用于数值。字符串长度、列表元素个数、文件大小……只要是有「边界」的地方,都适用。

3.2.3 实战案例:购物车数量限制

需求:购物车中单个商品数量 1-99 件。

我设计的用例:

测试数据 预期结果 说明
0 提示「数量不能为0」 下边界-1
1 添加成功 下边界
2 添加成功 下边界+1
98 添加成功 上边界-1
99 添加成功 上边界
100 提示「数量不能超过99」 上边界+1

我曾经遇到过一个问题。开发把 if (count > 0 && count < 100) 写成了 if (count >= 0 && count <= 100)。结果 0 和 100 都通过了。边界值测试直接抓到了这个 bug。

3.3 因果图法:理清复杂逻辑关系

等价类和边界值,主要针对单个输入。但现实中的系统,输入之间是有关系的。比如:

  • 「如果选了A,就不能选B」
  • 「只有满足C和D,才能执行E」

这时候,因果图法就派上用场了。

3.3.1 因果图的核心思想

因果图,说白了就是画逻辑关系图。

  • :输入条件
  • :输出结果
  • 关系:与、或、非、异或等

我一般分四步走:

  1. 找出所有输入(因)和输出(果)
  2. 画出因果关系图
  3. 把图转成判定表
  4. 根据判定表写用例

3.3.2 常见的逻辑关系

关系 符号 说明 例子
恒等 = 因成立,果就成立 输入正确密码 → 登录成功
~ 因不成立,果才成立 不是管理员 → 隐藏管理菜单
所有因都成立,果才成立 有账号 + 有密码 → 可以登录
任一因成立,果就成立 刷卡成功 或 扫码成功 → 开门
异或 有且仅有一个因成立 选「男」就不能选「女」

3.3.3 实战案例:优惠券发放规则

需求是这样的:

  • 用户等级是VIP,或者消费金额超过1000元
  • 并且用户没有领取过该优惠券
  • 满足以上条件,发放优惠券

咱们来画因果图。

因:

  • A:用户是VIP
  • B:消费金额 > 1000
  • C:未领取过该优惠券

果:

  • X:发放优惠券

关系:

  • (A ∨ B) ∧ C → X

转成判定表:

A B C X
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 0
1 0 1 1
1 1 0 0
1 1 1 1

你看,8种组合,一目了然。哪些能发券?第4、6、8行。哪些不能?剩下的5行。

我的经验:因果图法适合逻辑复杂的场景。但别滥用。如果输入条件超过5个,判定表会变得很大。这时候可以考虑用正交实验法,咱们后面会讲。

3.4 三种方法的配合使用

最后,我聊聊这三个方法怎么搭配。

  • 等价类划分:先分大类,确定测试范围
  • 边界值分析法:在边界上深挖,抓边界bug
  • 因果图法:处理输入之间的逻辑关系

我一般的设计流程是:

  1. 用等价类划分,列出所有输入的大类
  2. 对每个数值类输入,补充边界值
  3. 如果输入之间有逻辑关系,用因果图梳理
  4. 合并去重,得到最终的测试用例集

举个例子。一个登录功能:

  • 用户名:等价类 + 边界值(长度边界)
  • 密码:等价类 + 边界值(长度边界)
  • 验证码:等价类(正确/错误/过期)
  • 登录按钮:因果图(用户名正确 ∧ 密码正确 ∧ 验证码正确 → 登录成功)

这样一套组合拳下来,覆盖率基本能到90%以上。

最后提醒一句:方法只是工具,别为了用方法而用方法。我见过有人把等价类分得特别细,结果用例数量翻了好几倍。没必要。核心是「用最少的用例,覆盖最多的场景」。

好了,今天先聊到这儿。下一讲咱们继续聊场景法、正交实验法和错误推测法。到时候见。