ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

等价类测试方法详解:从原理到实战用例设计

等价类测试方法详解:从原理到实战用例设计 1. 等价类测试从测不过来到精准打击干了这么多年测试最怕听到的一句话不是又出bug了而是这个功能明天上线你今晚把所有情况都测一遍。所有情况一个输入框可能塞得下全宇宙的字符一个下拉框能组合出几十万种场景真要穷举测试给你一年时间也不够用。这时候等价类测试就是救命稻草。等价类测试的核心思想一句话就能讲明白把输入域按照测不测都一样的原则划分成若干个子集合每个子集合里随便挑一个代表值去测测过了就等于整个集合都过了。它不像边界值分析那样盯着临界点抠细节也不像因果图那样梳理复杂逻辑关系它就是一门分堆的艺术——分得好测试覆盖率能到90%以上分得烂测到上线都测不完。这篇内容适合刚入行的测试小白也适合写测试用例写到吐的资深工程师。我会从原理讲起再用一个完整的注册页面案例带着你把等价类划分从头到尾走一遍最后把我踩过的坑和排错经验一并倒出来。读完你就能理解为什么有些测试用例设计出来是浪费时间的也能自己动手把任意一个页面的输入场景拆得明明白白。2. 等价类划分的底层逻辑与设计思路2.1 为什么代表值能代表整个集合你可能会想从每个集合里随便挑一个值去测这靠谱吗万一恰好挑中的那个值没问题集合里另一个值有问题呢这个疑虑很合理但等价类划分有一个前提系统对同一等价类内的数据处理路径是完全一致的。拿登录页的用户名输入框来说假设规则是6到12位字母数字组合。我随便输入abc123系统走的是校验长度→校验字符类型→校验是否重复→写入数据库这条路。我换成xyz789系统走的还是这条路。这中间没有任何一个分支会因为我输入的是abc而不是xyz而产生差异那么这两个输入在系统眼里就是等价的。我测一个就等于测了无数个。这就是等价类测试的理论基石——当程序对一类数据的处理逻辑完全相同时测试其中一个数据就等价于测试这一类数据。它本质上是从庞大的输入空间中寻找行为一致性用数学上的集合论做抽象把无穷的测试场景压缩成有限的测试集合。2.2 有效等价类与无效等价类的本质区别划分等价类时最基础也最重要的两个概念就是有效等价类和无效等价类。有效等价类是指符合需求规格说明书要求、程序应当接受的输入数据集合。比如上面说的6到12位字母数字组合abc123、Test1234都属于有效等价类。测试有效等价类的目的是验证系统在正常输入下能不能正确工作。无效等价类则恰恰相反它是指不符合需求、程序应当拒绝的输入数据集合。比如ab长度不足、1234567890123长度超限、abc#123含特殊字符、空值都属于无效等价类。测试无效等价类的目的是验证系统在异常输入下能不能优雅地报错而不是直接崩掉。很多新手只盯着有效等价类测觉得我输入正常数据能过就行。这种想法会带来灾难性后果——因为用户永远不会按你的预期输入。用户可能手滑多打一个字符可能复制粘贴进来一段带空格的内容可能用输入法打出全角字符这些不正经的输入恰恰是线上bug的高发区。所以设计用例时无效等价类的数量通常比有效等价类还要多。2.3 等价类测试的适用边界它解决什么不解决什么等价类测试不是万能的它有清晰的适用边界。它最擅长的是处理纯输入输出型的场景——表单校验、参数处理、数据转换、接口入参校验。这类场景逻辑相对独立输入和输出之间的关系比较直接用等价类划分能够快速覆盖大部分情况。但遇到下面几类场景等价类测试就不够用了逻辑组合复杂的场景比如当用户是VIP且订单金额满100元且使用优惠券时享受8折优惠这种多个条件联合判定的逻辑需要用判定表或因果图来梳理。状态流转相关的场景比如订单从待付款到已付款到已发货的状态机切换需要关注触发条件和状态迁移单纯划分输入等价类解决不了问题。数据关联性强的场景比如区间查询里起始日期必须早于结束日期两个字段之间有关系不能简单地各自划分等价类。我在实际项目中通常把等价类测试作为第一层防线先用它把单字段的输入覆盖做扎实再用边界值分析补临界点的漏洞最后用场景法或判定表处理复杂业务逻辑。多层方法配合使用才能真正把测试做透。3. 等价类划分的完整步骤与实操要点3.1 第一步识别输入条件圈定测试范围拿到一个功能需求先别急着写用例。第一步是把所有可能的输入条件完整地列出来。这个步骤看似简单实际上最容易遗漏因为很多输入条件是隐藏的。以注册页面为例表面上输入条件就三个——用户名、密码、确认密码。但完整列出来你会发现用户名长度、字符类型、是否必填、是否允许重复密码长度、字符类型大小写/数字/特殊字符、是否必填确认密码是否与密码一致、是否必填隐含条件是否允许空格、是否区分大小写、是否有限制连续字符、是否禁止纯数字我做了一个检查单来确保自己不遗漏输入条件先看页面上的可见输入框再看交互中的隐藏输入然后看接口文档里的入参约束最后翻后端代码确认数据库字段的校验规则。需求文档里写了的不一定全需求文档里没写的更要仔细看。3.2 第二步按规则划分等价类建立映射表把输入条件识别清楚后接下来就是核心环节——划分等价类。这个过程有一个标准化的思考框架我把它叫做三问法则这个输入允许哪些值有效等价类这个输入拒绝哪些值无效等价类每个允许/拒绝的边界在哪里为边界值分析做准备以用户名这一项为例假设需求是6到20位字母或数字且不能以数字开头划分结果如下等价类类型具体描述代表值有效等价类6到20位字母开头后续是字母或数字abc123有效等价类恰好6位字母abcdef有效等价类恰好20位字母数字混合a1b2c3...20位无效等价类小于6位abc无效等价类大于20位a1b2...21位无效等价类以数字开头1abcde无效等价类含特殊字符abc123无效等价类含空格abc 123无效等价类空值不输入注意看有效等价类不止一个无效等价类也不止一个。每个被规则分割开的区间只要系统处理逻辑可能不同就应该独立成一个等价类。3.3 第三步为每个等价类生成测试用例等价类划分完毕后生成测试用例就变得非常机械了几乎不需要动脑筋。原则很简单每个有效的等价类至少覆盖一次每个无效的等价类单独一条用例。这里有一个极其重要的原则必须记住无效等价类不能合并。什么意思就是说一条测试用例里如果同时有多个无效输入你只能让其中一个无效其他输入必须保持有效。为什么要这样因为如果你输入的用户名非法、密码也非法系统报错了你能判断这个报错是因为用户名还是因为密码吗无法判断。报错信息可能只提示第一个错误导致另一个问题被隐藏。所以一条用例只制造一个变量才能准确锁定问题源头。而有效等价类则可以合并因为输入都合法时系统应该能正常走完整条流程合并测可以节约用例数量。比如正确的用户名 正确的密码 一致的确认密码完全可以放一条用例里验证。3.4 第四步与边界值分析配合补齐临界点漏洞等价类测试有一个天然盲区——它关注的是集合内部的代表性而边界恰恰是程序员最容易写错逻辑的地方。比如判断长度大于等于6代码里写成了长度大于6那长度为6的输入就被错误拒绝了。这种bug用等价类测试根本发现不了因为你在有效等价类里取的代表值大概率是abc123这种7位的不会精确落在6位上。所以实际工作中我从来不会让等价类测试孤军奋战。等价类划分完成后紧接着就对每个等价类的边界值进行补充分析取刚好处在边界上的值、边界值加一、边界值减一。拿上面的用户名规则来说长度边界就是6和20那我至少要测长度为5、6、7、19、20、21这六种情况。仅这一个字段就用掉了6条用例。搭配组合起来一个原本要写二三十条用例的注册页面用等价类边界值方法通常十条以内就能覆盖得相当扎实。4. 从零手写一套登录注册模块的等价类测试用例4.1 需求文档规则边界与约束条件光说不练假把式下面我用一个实际项目里非常典型的用户注册功能带大家走一遍完整的等价类测试用例设计过程。需求规格说明书里的原始描述是这样的用户名必填6到20个字符仅允许字母、数字且不能以数字开头密码必填8到16个字符必须同时包含大写字母、小写字母和数字确认密码必填必须与密码完全一致所有字段前后不能包含空格用户名在系统中必须唯一注意需求文档本身就隐含了一个很容易被忽略的条件前后不能包含空格。空格算不算字符如果用户输入 abc123 到底是该自动去除空格还是直接报错需求里没写但测试肯定得覆盖。我实际遇到过很多次这种情况——需求文档含糊不清代码逻辑自己拿主意测试与开发理解不一致最后线上出了事故。作为测试人员遇到这种需求未明说但影响行为的点一定要尽早拉上开发和产品确认而不是想当然。4.2 逐字段拆分从规则到等价类映射用户名字段把需求转化为等价类划分见下表等价类ID类型规则描述代表输入U1有效6位字母开头字母数字组合abc123U2有效恰好6位全字母abcdefU3有效20位字母数字混合a1b2c3...凑满20位U4无效少于6位abcU5无效多于20位a1b2c3...凑到21位U6无效以数字开头1abcdeU7无效包含特殊字符abc123U8无效包含空格中间abc 123U9无效首尾包含空格 abc123 U10无效空值不输入这里特别说明一下为什么U1和U2要分成两个等价类因为它们的测试目的不同——U2验证的是恰好等于最小长度时能否通过属于边界值的思想提前渗透进来而U1是常规有效值。不过在纯等价类阶段它们确实都属于有效等价类但按照我多年的一线经验把边界上的有效值单拎出来与边界值分析衔接用例设计会更顺畅。密码字段需求是8到16个字符必须同时包含大写字母、小写字母和数字等价类ID类型规则描述代表输入P1有效8位包含大小写字母和数字Abc12345P2有效16位包含大小写字母和数字Aa1Bb2Cc3Dd4Ee5FfP3无效少于8位Abc1234P4无效多于16位Aa1Bb2Cc3Dd4Ee5Ff6GgP5无效只有大写字母和数字没有小写ABC12345P6无效只有小写字母和数字没有大写abc12345P7无效只有字母没有数字AbcdefghP8无效空值不输入P9无效包含特殊字符Abc1234注意P9是我额外加的。需求说的是必须同时包含大写字母、小写字母和数字并没有说不能包含特殊字符。那密码里出现到底算不算合法这是一个典型的需求未明确字段。正确做法是找产品确认而不是自己拍板。我在案例中默认规则是仅允许大小写字母和数字因此将特殊字符归为无效等价类但这个决策必须记录在测试评审记录中让项目组知晓。确认密码字段等价类ID类型规则描述代表输入C1有效与密码完全一致与密码输入相同C2无效与密码不一致大小写不同密码是Abc12345这里输abc12345C3无效与密码不一致内容不同密码是Abc12345这里输Xyz67890C4无效空值不输入确认密码字段相对简单它的核心校验就是与密码是否一致这个一致性本身就分了大小写敏感和不敏感两种可能。包括C2这个场景就是为了验证系统是否区分大小写——如果需求说完全一致那么大小写不同应当报错。4.3 组装测试用例有效合并、无效分离等价类划分完后开始组装测试用例。依据前面说的原则有效等价类尽量合并无效等价类逐条独立。我先设计一条快乐路径用例把所有有效等价类串在一起TC01用户名输入abc123U1密码输入Abc12345P1确认密码输入Abc12345C1——预期结果注册成功跳转登录页。接下来是为用户名无效等价类设计的用例密码和确认密码始终保持有效值TC02用户名abcU4密码Abc12345确认密码Abc12345——预期结果提示用户名长度至少6位。TC03用户名a1b2c3d4e5f6g7h8i9j0k1U521位密码正确——预期结果提示用户名长度不能超过20位。TC04用户名1abcdeU6密码正确——预期结果提示用户名不能以数字开头。TC05用户名abc123U7密码正确——预期结果提示用户名只能包含字母和数字。TC06用户名abc 123U8密码正确——预期结果提示用户名不能包含空格。TC07用户名 abc123U9密码正确——预期结果提示用户名不能以空格开头或系统自动去空格。TC08用户名不输入U10密码正确——预期结果提示请输入用户名。然后是密码字段的无效用例用户名用有效值确认密码用与密码一致的值TC09用户名abc123密码Abc1234P3确认密码Abc1234——预期结果提示密码长度至少8位。TC10用户名abc123密码Abc12345678Abc1217位P4确认密码相同——预期结果提示密码长度不能超过16位。TC11用户名abc123密码ABC12345P5无小写确认密码相同——预期结果提示密码必须包含小写字母。TC12用户名abc123密码abc12345P6无大写确认密码相同——预期结果提示密码必须包含大写字母。TC13用户名abc123密码AbcdefghP7无数字确认密码相同——预期结果提示密码必须包含数字。TC14用户名abc123密码Abc1234P9含特殊字符确认密码相同——预期结果提示密码不能包含特殊字符。最后确认密码字段的无效用例TC15用户名abc123密码Abc12345确认密码abc12345C2——预期结果提示两次输入的密码不一致。TC16用户名abc123密码Abc12345确认密码Xyz67890C3——预期结果提示两次输入的密码不一致。TC17用户名abc123密码Abc12345确认密码不输入C4——预期结果提示请再次输入密码。数一下总共17条用例。如果不做等价类划分穷举各种输入组合这个页面的用例量轻松过百而且很多还是重复劳动。通过等价类方法我们用一个相当紧凑的用例集覆盖了每一个有效规则和每一个无效规则。4.4 测试数据选择的细节经验代表值的选择也有讲究。我见过很多新手随便填aaaaaa、12345678这类数据能用但不够好。选择代表值时尽量选择有业务意义、易于识别的数据方便后续排查问题。更重要的是每个等价类的代表值之间差异要大避免两个等价类取到几乎一样的数据导致测试结果无法区分。比如用户名有效等价类选abc123无效等价类就不能选abc124这种差一位的因为系统对它们的校验路径几乎相同测试效果会被稀释。另外我习惯在用例表格中加一列等价类ID这样一旦测试失败我可以快速回溯到具体是哪个等价类的哪个规则出了问题而不是对着输入值猜上下文。这在回归测试和缺陷定位时能节省大量时间。5. 等价类测试的常见误区和排查技巧5.1 误区一忽视无效等价类只测正常路径这个误区在新手身上出现得最多。我刚带团队时让新人写测试用例交上来的东西清一色的用户名正确密码正确注册成功完全不考虑异常输入。问他们为什么不测9位长度、不含数字的密码他们的回答出奇一致用户不会这么输吧用户真的会这么输。我在生产环境里见过太多匪夷所思的输入有人在手机号框里填了110然后问为什么注册不了有人复制粘贴网页内容整段粘进地址栏还有人拿键盘猫踩出来的#%……当密码。测试要做到的不是替用户筛选合理输入而是保证系统对一切输入都有可预期的正确响应。5.2 误区二无效等价类一条用例塞多个无效值这在前面已经强调过但我还要再啰嗦一遍因为它真的太容易犯了。尤其是测试人员赶进度时恨不得一条用例验证完所有报错场景。你输入一个无效用户名、一个无效密码、一个不匹配的确认密码系统确实报错了但报的是哪个字段的错误是不是所有错误校验都生效了全被一次报错掩盖了。正确做法是每条无效用例只引入一个无效变量其他输入保持有效。这样定位bug时你能斩钉截铁地说问题就出在用户名长度校验而不是我也不知道为什么报错反正数据有问题。5.3 误区三等价类划分粒度不一致有的字段你分了5个等价类另一个类型相似的字段你只分了2个。这种情况在多人协作编写测试用例时特别常见因为每个人对规则的理解深度不一样。解决方法是做个简单的检查单每个输入条件至少覆盖合法、非法、空值、边界四个维度遇到有特殊规则的字段再额外增加等价类。把检查单固定成模板团队里所有人共用时间长了划分粒度就趋同了。我在组内推的就是这样一张模板必填性检查、长度检查、类型检查、格式检查、唯一性检查、一致性检查。每个字段按模板逐项过一遍等价类完整度有保障也不会漏项。5.4 排查实战一条等价类用例失败后的定位过程有一次测试一个搜索框需求是支持中文、英文和数字长度1到50个字符。我按等价类划分好后执行到50个字符的中文关键词这条用例时搜索结果页直接白屏了。排查步骤是这样的第一确认问题是不是稳定复现。重复执行三次每次都白屏确认不是偶发网络问题。第二缩小复现范围。把关键词从50个字符逐步减少发现49个字符时正常50个字符时白屏。这个现象说明问题出在长度边界而不是中文编码。第三查看后端日志。发现请求确实发出去了但响应超时了。进一步跟踪SQL日志发现这个关键词被拼进了一个模糊查询语句50个字符的中文让这个查询语句生成的SQL执行计划极其低效导致数据库查询超时。第四回到需求层面确认。这是个搜索框不是数据库压力测试工具50个字符的输入合法但系统没有对该长度做性能保护。测试结论从功能bug升级为性能缺陷提交缺陷单时把完整的等价类信息和复现步骤都附上了。这个案例给我们的启发是等价类测试不只暴露功能逻辑问题也可能暴露性能和稳定性问题。当一条看似普通的等价类用例爆出意外结果时不要急着修改代表值绕过它而是要深挖根因。那些藏得很深的问题往往藏在等价类中最容易被忽略的边界角落。5.5 工具辅助当等价类测试遇上自动化等价类划分是测试设计的方法论它和自动化测试工具天然契合。拿到等价类用例后可以用数据驱动的测试框架把测试步骤和测试数据分离每一行代表一个等价类的测试数据框架自动循环执行。举个例子参数化后的测试用例大概长这样import pytest pytest.mark.parametrize(username,password,confirm,expected, [ (abc123, Abc12345, Abc12345, 注册成功), (abc, Abc12345, Abc12345, 用户名长度至少6位), (1abcde, Abc12345, Abc12345, 用户名不能以数字开头), (abc123, Abc1234, Abc1234, 密码长度至少8位), (abc123, ABC12345, ABC12345, 密码必须包含小写字母), (abc123, Abc12345, abc12345, 两次输入的密码不一致), ]) def test_register(username, password, confirm, expected): # 调用注册接口断言返回结果包含expected ...这段代码最大的好处是需求变更了或者新增了规则直接在数据列表里加一行就行测试代码完全不用改。等价类划分的结果直接沉淀成自动化测试的数据资产回归测试时全量跑一遍几分钟出结果。6. 最后想说的一点经验做了这么多年测试接触过各种用例设计方法等价类测试始终是我用得最顺手、出效果最快的一个。它不像因果图那样需要把整个业务逻辑盘得清清楚楚才能动手也不像场景法那样要绞尽脑汁编各种用户故事。它简单、直接、有效只要你能静下心把一个一个输入条件列全、把规则一条一条掰开揉碎你的测试用例质量就已经超越了大多数同行。我个人在实际项目中还有一个使用习惯每次接到新需求先花15分钟把核心字段的等价类划分表画出来直接贴在测试用例文档最前面。开发自测的时候发给他们参考产品评审的时候拿出来对齐需求理解测试执行的时候对照着逐条验证。一份等价类表能同时作为沟通工具、测试设计和验收标准使用价值远不止写用例这一步。如果这篇文章能给你留下一个可执行的方法我希望是找一个你最近正在测的功能按识别输入条件→划分等价类→有效合并→无效分离的顺序尝试设计一套用例。做一次你就真正掌握它了。
返回列表