等价类划分法(上):有效等价类与无效等价类

很多测试新手拿到一个输入框,第一反应就是「把所有可能的数字都试一遍」。嗯,这种思路我年轻时也干过 —— 结果一个简单的电话号码字段测了三天,还没测完。后来带我的老测试丢过来一句话:「你这不是测试,是穷举。等价类划分搞懂了再说话。」

好,今天咱就把这块硬骨头啃下来。先看一张整体结构图,帮你建立全局印象。

等价类划分法核心概念 等价类划分法 有效等价类 无效等价类 符合规则的输入 取一个代表值 违反规则的输入 每类各取一个代表值 合并设计测试用例 核心理念 将输入的无穷集合划分为若干个子集(等价类) 每个子集内任意一个值都能代表整个类的测试效果

什么是等价类划分?

说白了就是「分门别类」。你把所有可能的输入数据归到几个组里,每组里面的数据对程序来说行为是一样的。我只要从每个组里随便挑一个值测一下,就能代表整个组。

举个例子,一个输入框要求「年龄:1-120之间的整数」。那 -1、0、1、60、120、121、'abc' 这些值该怎么处理?通过等价类划分,我们把它抽象成几个小组:

  • 有效等价类:1~120 之间的整数(一个组)
  • 无效等价类:小于1的整数、大于120的整数、非整数(小数、字母、特殊字符、空值等)—— 这些都是不同的组

你看,本来要测成千上万个数,现在只需要测几个代表值就够了。效率直接起飞。

我个人习惯:每次拿到需求,先在纸上把「正常情况」和「异常情况」的边界画出来,然后分别找代表值。这个习惯帮我节省了60%以上的无效测试时间。

有效等价类

有效等价类就是「程序应该正常处理的输入」。说白了,就是符合需求规则的那些数据。

比如一个密码字段,规则是「6-12位字母数字组合」。那有效等价类就是长度为6-12、且只包含字母和数字的字符串。在这个范围内,不管你输入 'abc123' 还是 'xYz890AbC',程序的行为预期是一样的 —— 都通过。

所以有效等价类 一般只有一个(除非规则内部还有多个分支)。

要点:有效等价类的代表值要覆盖「正常范围内的典型值」,不要刻意选边界上的值(边界值分析法会在后面单独讲,别混了)。

无效等价类

无效等价类则是「程序不应该正常处理的数据」。它们触发的应该是错误提示、拒绝或异常处理。

你想想看,用户可不会乖乖按你的规则来。他们可能会输入负数、超大数字、空字符串、字母、特殊符号、甚至 SQL 注入语句。每一个违规的方向,都应该是一个独立的无效等价类。

为什么无效等价类比有效等价类多? 因为规则只有一条「正确的路」,但偏离的方式有无数种。每一个偏离方式都是一个新的等价类。

输入条件 有效等价类 无效等价类
年龄(1-120整数) 1~120的整数 小于1的整数、大于120的整数、小数、字母、特殊字符、空值
手机号(11位数字,以1开头) 11位数字,且以1开头 少于11位、多于11位、不以1开头、含字母、空值
密码(6-12位字母数字) 6-12位字母数字组合 少于6位、多于12位、含特殊字符、纯数字、纯字母、空值
踩坑提醒:我曾经犯过一个低级错误 —— 把「小于1的整数」和「大于120的整数」合并成一个无效等价类,认为它们都属于「范围外」。结果程序对负数和大数的错误提示完全不同(一个是「年龄不能为负」,另一个是「年龄不能超过120」)。所以这两个必须分开测。

划分等价类的通用步骤

好,理论讲完了,咱们来点实在的。我一般按这四步走:

  1. 识别输入条件 —— 每个输入框、下拉列表、选择框都是独立的输入条件。
  2. 划分有效等价类 —— 只要规则没拆分,通常就是1个。
  3. 划分无效等价类 —— 逐条违反规则的方向,每个方向都是1个类。
  4. 为每个等价类选一个代表值 —— 保证代表值严格属于该类,且不与其他类别重合。

来看一个完整的代码级例子。假如你测的是一个登录界面的「用户名」输入框,需求是「4-20个字符,只能包含字母、数字、下划线」。

// 伪代码:测试用例设计(基于等价类划分)
// 有效等价类:长度4-20,只含字母/数字/下划线
// 代表值: "User_123" (长度8,合规)

// 无效等价类1:长度小于4
// 代表值: "ab" (长度2)
// 预期结果:提示"用户名至少4个字符"

// 无效等价类2:长度大于20
// 代表值: "abcdefghijklmnopqrstuvwxyz12345" (长度30)
// 预期结果:提示"用户名不超过20个字符"

// 无效等价类3:包含非法字符(如空格、@、#等)
// 代表值: "user name"
// 预期结果:提示"只能包含字母、数字、下划线"

// 无效等价类4:空值
// 代表值: "" 
// 预期结果:提示"用户名不能为空"

你肯定注意到了,上面我写了4个无效等价类。如果需求里还有「大小写不敏感」的规则,那有效等价类可能还要拆成大写组合、小写组合。看,实际工作中等价类的数量没有定数,取决于规则细节。

一个小技巧: 当你拿不准某个方向是否该独立成一个等价类时,问自己一个问题:「这个输入和另一个输入,程序给出错误提示的文案会不会不一样?」只要有可能不同,就拆开。

常见误区

聊几个我踩过的坑,希望你别再掉进去。

  • 把有效等价类当成唯一测试目标 —— 只测正确的数据,忽略无效类。结果上线第一天用户乱输一个字母,系统直接崩溃。
  • 无效等价类合并过度 —— 上面说过了,「小于最小值」和「大于最大值」不是同一个错误逻辑,必须分开。
  • 代表值选得太激进 —— 比如有效类的代表值选了个边界值(比如1或120),边界测试和等价类测试混在一起,导致边界出问题时分不清是等价类覆盖不全还是边界本身的问题。建议:等价类代表值取中间值,边界值单独测。
避坑指南: 我曾经在一个支付模块的测试中,把「金额为0」和「金额为负数」当作同一个无效等价类处理(因为都是“非法金额”)。结果程序对0的处理是「不弹提示直接返回成功」,对负数才弹提示。一个线上事故就这么来的。从那以后,只要程序逻辑上有任何不同分支,我一定拆成独立等价类。

有效等价类与无效等价类的对比总结

维度 有效等价类 无效等价类
定义 符合规则、程序应正常处理的输入 违反规则、程序应拒绝或异常处理的输入
数量 通常1个(规则无分支时) 多个(取决于规则违反的方向数)
代表值选取 选典型中间值,避免边界 每类选一个典型的违规值
测试目标 验证核心功能正确可用 验证容错和异常处理能力
常见遗漏 较少(因为好理解) 极其容易遗漏(尤其是空值、超长、特殊符号等)

最后说一句,等价类划分法是测试设计的基础,也是性价比最高的方法之一。你别觉得简单就轻视它 —— 我见过很多五年经验的测试,还在因为等价类划分不清导致漏测。把有效类和无效类的逻辑想透了,你的测试覆盖率至少翻一倍。