尧图精选

等价类划分与边界值分析实战:从三角形问题到测试思维

🕒 发布时间:2026/10/2 21:13:32 📁 来源:尧图网络
1. 先说头脑中的基础等价类和边界值的本质我一直觉得黑盒测试入门最绕不开的两板斧就是等价类划分法和边界值分析法。很多同学第一次接触这两个词都是从“三角形问题”这个经典练习开始的。说实话这题目看起来很简单三个数判断能组成什么三角形但真要把测试用例设计得滴水不漏里面的门道远比想象中多。先聊一个更底层的认知黑盒测试的核心思路是把被测程序当成一个不透明的黑盒子我们不看内部代码只通过输入和输出来判断功能是否正确。那问题就来了面对一个无限大的输入空间你不可能穷举所有输入去验证这时候就需要一种方法用尽可能少的测试数据覆盖尽可能多的典型场景。等价类划分法解决的就是这个问题而边界值分析法解决的是“等价类里最容易藏bug的那批值”的问题。等价类划分法的核心思想我习惯用一个比喻来解释假设你要测试一台自动售货机它只收1元、5元、10元的纸币这时候你没必要拿100张不同序列号的1元纸币去测因为机器处理它们的方式完全一样。你只需要从“1元”“5元”“10元”这三类里各抽一张验证即可。这里的每一类就是一个等价类——程序对同一等价类中的所有输入走的处理路径和产生的结果应当是等价的。边界值分析法则是从多年的工程实践中总结出来的规律程序最容易出错的区域恰恰是输入范围的边界附近。你说判断条件是“a大于0”还是“a大于等于0”在代码里可能就是差一个等号的事但程序在边界两侧的行为就完全不同。所以在设计测试用例时边界值和边界两侧的值必须重点覆盖这也是对测试充分性要求最高的区域。有意思的是这两种方法往往是配合使用的。等价类划分解决的是“测谁”的问题让你从海量输入中找到有代表性的类别边界值分析解决的是“在哪测”的问题让你在关键类别的边缘地带进行精准打击。两者互补缺一不可。三角形问题为什么成为教学经典因为它输入是三个数值输出有明确的分类等边、等腰、不等边、非三角形等价类分起来顺手边界条件又清晰实在是太适合用来练手了。不过你别小看这个题。我见过不少工作一两年的测试工程师让他用等价类划分法给三角形问题写用例写出来的东西还是漏洞百出。所以这篇文章我想把这个经典练习彻底讲透带着你完整走一遍需求拆解、等价类划分、边界值分析、测试用例编写的全过程顺带分享一些在实际项目中踩过的坑和总结出来的经验。2. 三角形问题需求拆解你可能忽略的三件事很多人拿到这个题第一反应就是这有什么好拆解的输入三个数判断是不是三角形是的话再判断什么类型完事了。但真到写测试用例的时候才发现需求里藏着不少需要自己拍板的“隐含条件”。2.1 输入域的三重隐藏条件第一层隐藏条件也是最容易被忽略的边长必须是正数。题目通常只说“输入三个数”但负数、0这种输入怎么办程序是应该报“输入错误”还是直接返回“不是三角形”这直接影响到你怎么划分无效等价类。我见过很多人写用例时只考虑了正数输入完全没有覆盖0和负数的情况这在实际业务里是要出大事的。你在银行系统里测转账金额能只测正数吗必须把0、负数、空值都考虑进去。第二层隐藏条件输入“三个数”这个“数”是什么类型是整数还是浮点数如果是浮点数精度怎么处理如果用整数那范围是多少题目里如果没写你就要自己定一个合理范围并在测试用例里明确标注。这看起来像是个小细节但当年有个真实案例一个系统用整数存储金额上限测试时只测了正常值结果上线后用户输入了一个超过上限的数系统直接崩溃。这就是输入范围没有明确、测试也没有覆盖的连锁反应。第三层隐藏条件“三个数”是怎么输入的是三个独立输入框还是在一行里用空格分隔如果要求用户输入三个整数但用户输入了“abc”系统是否做了类型校验类型校验不过时是弹提示还是默默忽略这些都属于程序处理“异常路径”的行为在设计无效等价类时必须进行分类。我的建议是拿到这类题目第一件事不是急着划分等价类而是先把需求“显式化”。你可以在纸上列出合法输入的取值范围是什么、非法输入有几类非数字、超范围、缺失、非法输入被拒时系统给出什么反馈。这样在后面设计用例时脑子里就有一张完整的“输入地图”了。2.2 输出端也是等价类大多数人对等价类划分的理解都停留在“输入域”这一个维度上但输出端同样存在等价类。程序最终的输出其实可以划分为等边三角形、等腰三角形、不等边三角形、非三角形、输入非法提示这几类结果就是输出域的等价类。为什么要关注输出域因为你的测试用例最终是要验证输出结果的。如果同一类输出对应着多条不同的内部处理路径而你只测了其中一条就可能漏掉bug。举个很实际的例子在三角形问题里等边三角形的返回结果可能是“Equilateral”等腰三角形是“Isosceles”非三角形是“NotATriangle”。你要是设计用例时只盯着“能不能组成三角形”却忘了区分“等腰”和“等边”那就会出现一个典型的bug——把等边三角形误判为等腰三角形的情况程序中是有可能出现这类分支错误或优先级错误的。所以在划分等价类时我会建议用“输入输出”双维度来交叉思考。输入侧有“构成三角形”“不能构成三角形”的区分输出侧有“等边”“等腰”“不等边”“非三角形”的结果。两边一结合你对程序的期望行为就非常清晰了。这其实是在模拟一种很重要的测试思维不要把用例设计当成“走个过场”而是当成“解剖程序的输入-处理-输出链路”。你越能精确地预测每种输入在输出端的表现越容易发现自己遗漏的测试盲区。2.3 明确需求还是自己补充需求最后聊聊这种题目里一个让人头疼的地方题目本身往往是不完备的比如没说边长是整数还是实数、没说是否考虑退化情形两边之和等于第三边、没说输入是否允许重复。这时候你作为测试工程师有两种选择一是根据常识做合理假设二是在测试说明中显式标注出假设。我个人的习惯是双重保险做一个合理假设然后在用例设计说明里写清楚“本设计假设边长范围为1到100的整数超出范围视为非法输入三角形判定不包括退化情况”这样评审用例时别人能一眼看出你做了哪些假设也就知道自己需要关注哪些潜在盲区了。这也是我特别想强调的一个点测试用例不是写给自己看的而是写给整个团队看的。你做的每一个假设都应该被显式记录。很多测试新人写用例习惯心里默认一个前提然后默默按这个前提设计结果评审时别人根本不知道他有这个前提用例的价值就大打折扣了。3. 等价类划分法完整实战从分类到用例表需求拆解做完就可以开始正式的等价类划分了。我会带着你从建立等价类清单开始一路走到可执行的测试用例表。3.1 建立有效等价类和无效等价类清单划分等价类的第一步是明确两个概念有效等价类和无效等价类。有效等价类是指满足输入要求、程序应当正常处理的输入集合无效等价类则是指不满足输入要求、程序应当拒绝并给出提示的输入集合。有效等价类验证的是“功能是否正常”无效等价类验证的是“异常处理是否可靠”两者同样重要。基于上面的需求假设三个整数边长范围为1到100输出为等边、等腰、不等边、非三角形四类我按输入数值本身将合法输入分为以下几类有效等价类V1三条边均为1到100范围内整数且满足任意两边之和大于第三边三边互不相等预期输出为不等边三角形。V2三条边均为1到100范围内整数其中两边相等且满足任意两边之和大于第三边预期输出为等腰三角形。V3三条边均为1到100范围内整数三边全部相等预期输出为等边三角形。V4三条边均为1到100范围内整数但不满足任意两边之和大于第三边即存在某两边之和等于或小于第三边预期输出为非三角形。无效等价类则按非法输入的不同维度来划分I1a小于1再细分为a0和a为负整数两个子类。I2b小于1。I3c小于1。I4a大于100。I5b大于100。I6c大于100。I7a为非整数比如小数字符串或特殊字符。I8b为非整数。I9c为非整数。I10输入缺失比如只有两个数。你可能注意到了我把“a不合法”“b不合法”“c不合法”分别拆成了不同的等价类。为什么因为程序对三个输入参数的处理通常是对称但独立的每个参数都可能在单独一条路径上出错。如果我把“任一输入小于1”合并成一个等价类测试时选a0那b或c的边界异常就测不到了。这里的关键经验是当程序的多个输入参数各自独立校验时每个参数的非法值都应单独成为一个无效等价类。3.2 覆盖原则与取舍等价类划分不是把类别列出来就结束了还有一个很关键的原则设计测试用例时有效等价类可以多个组合覆盖但无效等价类必须单独覆盖。这句话怎么理解有效等价类是为了验证程序在合法输入下功能正确所以可以在一条用例里同时覆盖多个有效类比如V1中a3、b4、c5一条用例同时满足了范围合法、三边不等、三角形成立三个条件效率很高。而无效等价类则不同一条用例里如果同时出现a-1和c200程序到底是因为哪个值非法而报错这就无法定位了。所以在覆盖无效等价类时我坚持“一次只触发一个无效条件”。不过这个原则也不是绝对的。举个例子如果程序对三个边长的非法值校验逻辑完全相同并且报错文案也一样那你确实可以只测一条但如果你不确定程序具体实现正确做法还是分开测用成本换取定位的确定性。3.3 一份可直接使用的等价类测试用例表按照上面的思路我写出了一份完整的等价类测试用例表你可以直接拿去做练习参考。用例编号abc预期输出覆盖等价类EC01345不等边三角形V1EC02335等腰三角形V2EC03454等腰三角形V2EC04545等腰三角形V2EC05333等边三角形V3EC06123非三角形V4两边之和等于第三边EC07125非三角形V4两边之和小于第三边IC01045输入非法I1IC02-145输入非法I1IC03305输入非法I2IC043-15输入非法I2IC05340输入非法I3IC0634-1输入非法I3IC0710145输入非法I4IC0831015输入非法I5IC0934101输入非法I6IC10abc45输入非法I7IC11345.5输入非法I7/I8/I9按题目假设取“非整数”场景IC12空45输入非法I10注意EC06这条用例1、2、3这个三元组里123恰好是“两边之和等于第三边”的退化情形。严格按几何定义这不能构成三角形。但在很多程序实现里开发者写判断条件时用的是“大于等于”还是“大于”行为是完全不同的。这一条用例我单独列出来就是为了覆盖这条隐藏的判定分支。在等价类划分时很多人会把“等于第三边”和“小于第三边”合并成一个等价类“不能构成三角形”实际上它们在程序里的分支往往是不同的应该分开覆盖。4. 边界值分析实战不是只在1和100处取样等价类划分帮我们找到了测试的对象但还有一个遗留问题U型范围内的临界位置程序最容易写错需要重点覆盖。这就是边界值分析法登场的时刻了。4.1 取值规则上点、离点、内点说到边界值分析法很多人第一反应是取边界值和边界值附近的值比如范围是1到100那就测1、100、0、101这四个值。这种理解是对的但不够完整。规范的边界值分析法需要你针对每个边界条件选择三类值上点边界上的点、离点离边界最近、同时属于边界另一侧的点、内点边界内取一个代表性的值。这里最容易搞混的是“离点”的概念当边界是闭区间时离点是边界内紧挨着上点的点当边界是开区间时离点是边界外紧挨着上点的点。就拿“边长合法范围是1到100”这个条件来说涉及两个边界下边界1和上边界100。对于下边界1上点就是1离点是0因为0是非法侧的最近点内点可以选50。对于上边界100上点是100离点是101内点还是50。这样每个边界对应3个取值两个边界共需要覆盖的典型值就是0、1、50、100、101这五个值。但边界值分析并不只是把它套在一维条件上。三角形问题有三个输入参数a、b、c每个参数都有各自的上下边界。如果严格做全组合边界值的组合数量会非常大。实际上针对边界值分析常用的策略是“每个维度单独取边界值其他维度取正常值”这样可以控制用例数量的同时覆盖到每个参数的边界。比如a取1、2、50、99、100时b和c取一个正常的中间值。4.2 三边关系的边界不只“两边之和等于第三边”很多人做三角形问题的边界值分析只关注了“边长范围”的边界却忽略了“三角形判定条件”本身也有边界。三角形判定条件是什么任意两边之和大于第三边。那这个条件的边界在哪就在“两边之和等于第三边”这个位置。前面等价类划分里我已经把它列出来了但在这里我要多说两句这个边界的危险程度比边长范围边界更高。因为程序员写这段判断时的典型错误就是把“大于”和“大于等于”用错这是非常容易发生的人为失误。我建议在边界值这部分专门围绕“两边之和恰好等于第三边”这个场景设计几条用例a1、b2、c3abc预期非三角形。a3、b5、c8abc预期非三角形。a1、b2、c2.9abc预期等腰三角形注意这里用了非整数如果你想严格限定整数可以用四舍五入到1、2、3的边界推演但在整型判断下这条用例不存在。a2、b2、c3.999abc预期等腰三角形在浮点数场景下有意义。如果你实际编码用整数实现时“a2、b2、c3.999”是无法输入的非整数所以这里的有效用例要考虑程序的数据类型。为了方便我们假设支持浮点数那么边界值分析还需要考虑“浮点数精度”问题——不过这属于程序实现的细枝末节测试设计层面上至少要把“两边之和等于第三边”作为一个专门的边界来对待。从实战经验看三角形判定里还有一个边界值得注意两边之差等于第三边。比如a5、b3、c25-32。在判定逻辑中如果程序员只用“两边之和大于第三边”作为唯一条件这个用例不会暴露问题但如果他在逻辑里加了减法的判断这里也可能踩坑。我的建议是在边界值分析阶段把“和等于第三边”和“差等于第三边”都测一遍成本不高收益是双保险。4.3 边界值测试用例合并与优化边界值分析产生的用例和前面等价类产生的用例天然存在很多交叉。比如等价类里EC01用了3、4、5边界值分析里如果也要测3、4、5那就没必要重复执行了直接合并即可。我实际操作时会用这样的合并策略先写一份边界值的取值列表然后对照等价类的用例集把已经覆盖的取值组合直接复用只补充那些没有覆盖到的。这样的话最后得到的用例数量会比两份用例简单相加少很多执行效率更高。下面是我整理的一份合并后的边界值相关用例用例编号abc预期输出覆盖点BD0115050等腰三角形a下边界BD0225050等腰三角形a下边界邻近点BD03505050等边三角形正常内点BD04995050等腰三角形a上边界邻近点BD051005050等腰三角形a上边界BD06112非三角形abc边界BD07111.9等腰三角形和略大于c浮点场景BD08112.1非三角形和略小于c浮点场景BD092100100等腰三角形等腰大边界组合BD101100100等腰三角形极端比值组合这里的BD06和BD07、BD08是刻意设计的“边界附近三态”用例刚刚等于、刚刚越过、差一点不到这三个位置对应程序里最经典的边界逻辑错误。你可能会觉得0.1的差距在整数判断下没有意义但如果你把需求放宽到浮点数这几条用例立刻就有价值了。我在实际项目中见过因为浮点精度问题导致三角形误判的案例所以这点还是值得强调的。5. 常见问题与排查技巧实录这一部分我想抛开理论讲讲在真实测试场景里设计这两种用例时最容易踩的坑以及一些我自己实践下来的工作习惯。5.1 等价类设计最致命的几个错误错误一无效等价类合并覆盖。前面我强调了一条用例里如果同时出现两个非法输入报错后无法定位。但实际操作中很多人为了赶时间仍然会图省事把多个无效情况塞进一条用例然后被开发一句“我这里两个校验都触发不了定位不了问题”搞得焦头烂额。老老实实分开测虽然用例数多一些但排查问题的效率是几何级提升的。错误二把“输入类型非法”和“输入范围非法”混为一谈。输入abc和输入-5在程序里大概率走的是不同的校验分支。你如果不分开测试就不知道程序对两种异常处理是否都正常。举个真实的例子一个表单校验组件对“非数字字符”的提示是“仅支持数字”对“超范围”的提示是“请输入1到100之间的数”但某次改版后非数字字符输入竟然走了超范围的提示这个bug如果不分开测很容易漏掉。错误三忽略“输入为空”这个等价类。很多测试用例里输入a、b、c的值都是非空的数字却漏了“某个参数为空字符串”的场景。在Web系统里这种场景太常见了前端可能拦住了必填校验但如果你测的是接口直接在报文里去掉一个字段后端校验是否健壮这就是需要无效等价类覆盖的场景。5.2 边界值法使用时的实战细节首先是“边界值到底取几个”的问题。规范的说法每个边界取上点、离点、内点三个值就够。但实际经验告诉我如果这个边界条件在代码里对应着数据库查询或金额计算我会额外加一个“边界外一个数量级”的值。比如范围是1到100我会加一条1000倍的用例看看程序是否对超大输入有保护逻辑。其次是“边界值不只是数值边界”。在三角形问题里类型的边界也很值得测比如输入一个非常长的字符串看看程序有没有做长度限制。输入一个像“1e10”这样的科学计数法字符串程序是把它解析为浮点数还是直接报类型错误这些都属于“输入解析”层面的边界很多时候比数值边界更容易暴露问题。最后是“组合边界的价值”。同时让两个参数处于边界值时可能会触发完全不同的处理分支。比如a1、b1、c1和a100、b100、c100从数值上看距离很远但它们都触发了“等边三角形”的输出分支。边界值分析如果只盯着单个参数你就发现不了这类组合场景下的异常。所以我在边界值用例里至少会安排几组多个参数同时处于边界位置的组合用例。5.3 从三角形问题迁移到真实业务的思路很多人学完三角形问题觉得这东西太玩具了工作里根本用不上。但我的观点恰恰相反三角形问题是“测试思维的微缩模型”它把输入分析、分类、边界识别、异常处理的通用思路浓缩在了一个极小的题目里。真实业务里等价类划分法最常用的场景是表单校验、查询条件、接口入参校验。比如你测一个注册功能用户名长度限制是6到20位那“6位”“20位”“5位”“21位”“空值”这几组用例本质上就是在做边界值分析。再比如测一个优惠券金额字段输入0元、负数、超过上限的值分别对应的就是无效等价类和边界值分析。从三角形问题到真实业务最大的区别是输入域从“一维数值”变成了“多维复杂对象”但方法的内核是一样的先把输入空间切分成若干有代表性的等价类再对类别边界进行定点打击最后把异常路径无效等价类逐一覆盖。这里我特别想分享一个习惯拿到需求后不要急着写用例先用一张A4纸把“合法输入的范围”和“非法输入的分类”画出来。这张图不需要发给任何人它就是你自己梳理需求的工具。几乎每一次画完这张图之后我都能发现需求描述里没说清楚的地方进而去找产品经理确认。这个过程就是等价类划分思维在真实需求分析中的价值。还有一个经验是运行测试用例时把“预期输出”写清楚。很多人在用例表里只写“功能正常”“报错”但到底期待什么报错文案、什么返回码都没写。这样即使程序出现bug你也很难判断是不是预期的bug。三角形问题里我要求自己写“预期输出为非三角形”而不是“正常”就是在训练这种对预期的精确性。写在最后的心得我始终觉得设计测试用例这件事功夫在“分析”而不在“写”。等价类划分法帮你建立分类感边界值分析法帮你建立敏感度这两者一旦练成你拿到任何需求都会下意识地思考这个输入的合法边界在哪哪些地方最容易出错这几个问题一旦在脑子里形成习惯写用例的速度和质量都会大幅提升。三角形问题虽然简单但它包含了黑盒测试设计里最核心的两个方法论值得反复练习。你可以试着把这个练习做点变体改成“日期合法性判断”“身份证号校验”“订单金额计算”用同样的思路去拆解需求、划分等价类、锁定边界练上几次你对这两种方法的掌握度就完全不一样了。最后分享一个我在实际项目中踩过的坑作为收尾吧有一次测一个订单系统金额取值范围是0.01到9999.99我用边界值分析把0.01、0.02、9999.98、9999.99、10000.00这些值都测了自认为覆盖得很周到。结果上线后有用户输入了0.00后端居然通过了校验生成了0元订单。我复盘时才发现我下意识把0.00当成了0.01的邻近点觉得它会在前端被拦下就没有专门设计这条用例。这个教训告诉我边界值分析里千万不要凭直觉判断“这个值肯定会被拦”你猜想的拦截逻辑在真实程序里未必存在。把每个边界点都老老实实测一遍才是唯一可靠的做法。希望这篇关于等价类划分法和边界值分析法的实战拆解能帮你把三角形问题吃透。如果你在练习中遇到了别的幺蛾子欢迎在评论区聊一聊我尽量回复。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →