软件测试用例设计实战:佣金问题等价类与边界值全解析 搞软件测试的人十有八九都遇到过这套经典练习“给你一个佣金计算需求请设计测试用例。”别小看它我见过不少简历上写着“精通测试用例设计”的人在这道题上翻车。原因很简单它表面上就是一道小学应用题三种零件各卖出多少件、单价多少、按销售额分档提成。可一到写用例的时候等价类划不划得清、边界值找不找得全、不同条件组合会不会漏才是真正的分水岭。这篇文章就用这个佣金问题做载体把测试用例设计的完整过程从头到尾捋一遍。适合三类人看刚入行的测试新人准备面试的候选人以及需要在团队里做测试设计内训的同伴。我会直接讲怎么做、为什么这么做、以及实际执行时踩过的坑。1. 需求拆解佣金问题的业务规则和隐含假设1.1 经典需求版本我这里用的是软件测试课程里最常见的佣金问题版本。某公司销售三种零件A、B、C单价分别为45元、30元、25元。销售人员每月上报三种零件的销售数量均为非负整数且每种数量不超过70件。系统需要根据输入计算出两个输出当月总销售额和应发佣金。佣金规则按销售额分三段提成销售额不超过1000元的部分佣金比例为10%超过1000元但不超过1800元的部分佣金比例为15%超过1800元的部分佣金比例为20%用公式写出来更清晰销售额 45 × A 30 × B 25 × C若销售额 ≤ 1000佣金 销售额 × 10%若 1000 销售额 ≤ 1800佣金 100 (销售额 - 1000) × 15%若 销售额 1800佣金 220 (销售额 - 1800) × 20%其中100是前1000元的10%提成220是前1000元提成100加上中间800元提成120的总和。这两个常数建议在用例设计之前先手算一遍因为很多预期结果写错源头就是这里。1.2 为什么这道题适合做测试设计练习佣金问题的魅力在于“需求短、规则清楚、坑却一点不少”。它有三个输入变量每个都有范围约束中间还有一个分段函数输出又分成销售额和佣金两项。这种结构天然覆盖了等价类划分、边界值分析、判定表驱动这三种最核心的黑盒测试设计方法而且业务本身贴近真实的计费系统练完可以直接迁移到电商提成、运费模板、阶梯折扣等场景。做这道题的时候很多新人会陷入一个误区以为测试用例就是随便填几组数字跑一遍对一下结果就行。实际上面试官或者带你的老测试想看到的是你能否从需求里提炼出边界条件能否识别出需求中没说清楚的地方能否用测试设计方法而不是“感觉”来生成用例。这才是一道好练习题的价值。1.3 需求里没写但设计用例前必须确认的事真实项目中不存在“需求一看就懂”的情况这道练习题也一样。以下是我每次带新人做这个练习时会要求对方先回答的几个问题佣金保留几位小数题目多半只说“佣金是多少元”但真实业务里佣金通常精确到分也就是0.01元。不确认清楚预期结果的小数位怎么定销售数量允许为0吗0件算正常上报还是异常数据经典题目里数量是非负整数那0是有效等价类。输入类型是什么UI输入框、接口入参测的范围不一样。如果是接口字符串、NULL、浮点数都可能传到服务器如果是表单前端可能会先拦截一部分。数量超过70怎么处理直接报错还是截断负数、小数、字符分别返回什么提示佣金计算如果出现浮点误差是四舍五入还是截断保留这一点在真实计费系统里最容易出线上事故。这些疑点应该在测试计划里写成“待确认问题”而不是自己拍脑袋定一套预期结果。等产品和开发给了明确结论再锁定用例。这一条本身就是测试用例设计的基本功。2. 测试设计方法怎么用不是堆用例而是防漏2.1 等价类划分先把大格子分出来等价类划分的核心思想是把无限多的输入归成有限几类从每类里取一个代表值去测认为这类输入的表现是一致的。对佣金问题来说可以这样划分输入A、B、C的取值分别都有有效等价类0 ≤ 数量 ≤ 70且为整数无效等价类数量 0无效等价类数量 70无效等价类数量为小数或非数值输出的等价类可以从销售额和佣金两个维度看销售额有效范围0 ≤ 销售额 ≤ 7000因为三个数量全为70时销售额是最大即 (453025) × 70 7000佣金结果有效范围0 ≤ 佣金 ≤ 1260全70时佣金 220 (7000-1800) × 20% 220 1040 1260佣金分段区间销售额 ≤ 1000、1000 销售额 ≤ 1800、销售额 1800这里有个新手容易掉进去的坑把“销售额区间”当成输入变量的边界。销售额是三个输入组合之后的结果不是直接输入值所以你不能只测A1000这种本身不合法的样例而是要通过调整A、B、C的数量让算出来的销售额恰好落在分段边界附近。2.2 边界值分析单变量边界和组合边界都不能漏边界值分析在等价类的基础上重点考察每个等价类的边界及其附近值。佣金问题里有两类边界必须分别处理。第一类是输入数量的边界。A、B、C各自的合法边界都是0和70所以合法边界内要覆盖0、1、69、70非法边界要覆盖-1、71。这个比较简单但要记住三个输入变量都要测不能只拿A举例。第二类是销售额分段边界也就是1000元和1800元这两个佣金阈值。难点在于你需要找出对应的A、B、C组合使销售额恰好等于这些阈值。这里有一个非常实际的数学限制45、30、25都是5的倍数所以无论怎么组合销售额一定是5的倍数。这意味着1001、1799这种值根本构造不出来边界附近的用例只能取最接近的可达值。我常用的构造方式是固定其中两个变量只调整第三个。比如固定A0、B0只调CC39销售额975落在第一档佣金97.5C40销售额1000正好是第一档的上边界佣金100C41销售额1025落在第二档佣金10025×15%103.75这样就把1000元边界的左右两侧都覆盖到了。1800元边界可以用A19、B3、C34来逼近销售额19×453×3034×25855908501795佣金100795×15%219.25再用A19、B4、C33销售额8551208251800佣金220。上下两组数据把第二档和第三档的交界处卡得死死的。2.3 判定表多条件组合防漏神器等价类和边界值适合处理单输入或单边界的场景但佣金问题存在多条件组合。三个数量是否合法加上销售额落在哪个档位组合起来很容易漏测。判定表在这里的价值就是强制枚举所有条件组合。条件桩可以设为A是否在合法范围是/否B是否在合法范围是/否C是否在合法范围是/否销售额所处的档位第一档/第二档/第三档动作桩则是提示“输入数量非法”计算销售额计算佣金返回销售额和佣金理论上三个合法性条件有8种组合再叠加三个销售额档位规则会比较多。但实践上不需要机械地为每个组合都造一条用例比如A、B、C都合法的8种覆盖每个档位各来几条而只要有一个非法就统一走提示逻辑。判定表的核心价值在于推动你思考哪些条件组合没有被覆盖而不是让用例数量膨胀。2.4 场景法和因果图怎么补充有的教材会在这道题里硬套因果图其实不必要。佣金问题是一个典型的纯计算函数因果图能画出来的“数量非法→提示错误”“数量合法→计算佣金”这种关系用等价类就足够表达。场景法更适合去测端到端流程用户打开录入页面、填写数据、点击提交、看到佣金结果。如果你在一个GUI系统里做佣金模块那场景法可以补几条冒烟用例比如连续提交、清空重填、页面刷新后的状态等。我的建议是做练习题阶段不要贪多等价类边界值判定表就够了。方法是为目的服务的一个函数模块非要上全量场景法反而会稀释真正重要的边界用例的价值。3. 可直接参考的测试用例清单3.1 功能与边界用例表下面是我整理的一套完整用例编号和预期结果都经过手算验证。设计依据列说明这一条用例到底覆盖了什么测试设计点。用例编号ABC预期销售额预期佣金设计依据TC-FUNC-011010101000100.00一般组合销售额正好等于第一档上限TC-FUNC-021010111025103.75第二档起始附近C加1越过1000TC-FUNC-03194331800220.00销售额正好等于第二档上限TC-FUNC-04195321805221.00第三档起始附近TC-FUNC-0500000.00最小合法组合TC-FUNC-0670707070001260.00最大合法组合TC-FUNC-0755550050.00第一档中间值TC-FUNC-083029282920444.00第三档中间值组合TC-BOUND-010101055055.00A的下边界TC-BOUND-021101059559.50A下边界1TC-BOUND-036910103655591.00A上边界-1TC-BOUND-047010103700600.00A上边界TC-BOUND-051003997597.50销售额1000左侧最近可达值TC-BOUND-061010101000100.00销售额1000精确边界TC-BOUND-071010111025103.75销售额1000右侧最近可达值TC-BOUND-08193341795219.25销售额1800左侧最近可达值TC-BOUND-09194331800220.00销售额1800精确边界TC-BOUND-10195321805221.00销售额1800右侧最近可达值注意TC-FUNC-03和TC-BOUND-09重复了实际项目里可以合并这里分开是为了说明“功能设计”和“边界设计”关注点不同。每一行我都会让新人手算一遍尤其是佣金很多人会把第二档的100元基础提成漏掉比如销售额1800直接算成1800×15%270那预期结果就全错了。3.2 非法输入与异常用例表非法输入的预期结果不一定是“抛异常”更合理的预期是“系统给出友好且明确的错误提示并且不计算佣金”。这条要在需求评审时和产品对齐否则开发会认为“你塞个负数进来我返回500也算合理”用例编号输入预期结果设计依据TC-INV-01A-1, B0, C0提示“数量不能为负”负数无效等价类TC-INV-02A0, B71, C0提示“单种数量不能超过70”超上限无效等价类TC-INV-03A0, B0, C1.5提示“数量必须为整数”小数无效等价类TC-INV-04A0, B0, Cabc提示“请输入数字”非数值字符TC-INV-05A空值, B0, C0提示“数量不能为空”空值输入TC-INV-06A-1, B71, Cabc按规则提示第一个错误或汇总所有错误多条件非法组合最后一条的预期结果尤其需要提前确认。如果系统设计为逐字段校验那-1会先被拦截如果设计为统一校验则可能一次性提示三个问题。两种实现都合理但测试断言必须跟着设计走。3.3 精度相关的用例佣金涉及小数浮点精度是必测点。我建议单独建一组用例专门验证小数位数和舍入规则。用例编号ABC预期销售额预期佣金说明TC-PREC-0100661650197.50650×15%计算结果存在二进制浮点误差风险TC-PREC-0200521300145.00300×15%45简单小数但不一定精确TC-PREC-032220201990238.00第二档第三档混合金额非整数TC-PREC-0400000.00零值边界检查是否出现-0.00为什么单独提1650这个值我用Python实测过650×0.15的结果在某些环境下会等于97.49999999999999再加上100就是197.49999999999997。如果程序直接把浮点数转字符串展示用户会看到197.49999999999997这就是缺陷。真实业务里佣金元以下都要四舍五入到分常见做法是用十进制类型或者把所有金额转成分整数再计算。测试时要确认实现方案再决定断言怎么写在自动化脚本里。3.4 需求追踪矩阵如果这是真实项目我还会做一张简单的追踪矩阵把每条测试用例和需求条目对应起来。佣金问题的需求条目可以拆成三部分数量合法性校验、销售额计算、佣金分段计算。需求项覆盖用例状态REQ-01 数量必须是非负整数且≤70TC-BOUND-01~04TC-INV-01~06已覆盖REQ-02 销售额45A30B25CTC-FUNC-01~08已覆盖REQ-03 佣金按销售额分三段计算TC-BOUND-05~10已覆盖REQ-04 金额保留两位小数TC-PREC-01~04已覆盖追踪矩阵的目的是回答“你测了什么、凭什么说测完了”这个问题。很多测试报告写得空泛一张矩阵比我写十句话都有说服力。4. 执行现场实录从用例到缺陷报告4.1 执行准备和前置条件用例设计好以后执行阶段反而相对机械但同样有讲究。首先要确定测试环境。佣金问题如果是个独立接口可以直接通过接口工具批量调用如果只能通过UI操作那就要准备好造数脚本或重复提交数据的操作路径。我通常会把用例表导出成CSV然后写个简单的参数化脚本跑一遍。跑之前先确认断言方式销售额是整数不一定有问题佣金是浮点数就必须约定误差范围。用JUnit的assertEquals(expected, actual, 0.001)或者Python的pytest.approx都可以。如果不约定误差范围很多用例会因为0.0000001这种噪声全挂这时候先别急着报bug先检查是不是断言写得太苛刻。4.2 典型缺陷边界判断写成了而不是≤这是佣金问题最经典的bug。需求说“销售额不超过1000元的部分按10%提成”正确的实现应该是 if (sales 1000)。开发很容易写成 if (sales 1000)。这时候销售额恰好等于1000的用例预期佣金是100实际代码会走进第二档按15%提成算出150。我这条用例执行完编号TC-BOUND-06状态Fail一张清晰缺陷报告缺陷标题销售额等于1000元时佣金多算50元复现步骤输入A10、B10、C10销售额恰好为1000点击提交实际结果佣金150元预期结果佣金100元严重程度高直接影响月度佣金结算正确性注意这里的“多算50”不是1000的5%吗1000×15%-1000×10%50对。缺陷报告里把业务影响写清楚开发修复优先级会更高。4.3 典型缺陷负数和超上限输入没有被拦截有的开发只写了佣金计算逻辑完全没做输入校验。A-10、B0、C0时销售额-450因为-450≤1000程序给出一条佣金-45元。这个缺陷比边界判断还严重因为财务系统里出现负佣金意味着用户可能要倒贴钱。报这个bug时我通常会在描述里附一句“建议在接口层统一做参数校验而不是依赖前端表单”。超上限同理A71、B0、C0时如果系统没拦截销售额3195照样算出第三档佣金但业务规则里每种数量上限70本意是防止录入错误数据。这类缺陷往往不是计算错是逻辑校验漏了。4.4 典型缺陷浮点精度引发的金额显示异常前面提到的1650用例如果开发用float类型直接存金额实际结果会在197.49999999999997附近。在自动化断言里用完全相等比较必挂但如果你会上这条用例并把它标记为Fail就得小心了。开发可能会说“这只是显示问题四舍五入一下就好了”但真实记账系统里处理顺序不同会导致一分钱差异所以这笔账要认真算清楚。我见过一个真实计费系统的案例某项目组为了省事用double做金额计算结果每月账单里总有几十条记录比人工核算差一分钱最后整个对账流程都被拖累。佣金问题这个练习题就是提前把这种教训以小而完整的形式暴露出来。4.5 用例执行结果汇总思路所有用例执行完我会按“通过/失败/阻塞”分类统计。失败用例统一关联到缺陷阻塞用例说明前置条件不满足比如页面还没开发完。一个合格的测试报告不只是数字还要包含对失败原因的分析哪些是功能实现错误哪些是需求歧义哪些是测试数据本身就设计错了。5. 从练习到实战自动化回归和通用资产沉淀5.1 用参数化用例做快速回归佣金问题非常适合练自动化测试因为它逻辑简单、预期好算、用例表结构清晰。给一个Python pytest的示例思路新手可以直接照着扩展import pytest def calc_sales(a, b, c): return 45 * a 30 * b 25 * c def calc_commission(s): if s 1000: return round(s * 0.10, 2) elif s 1800: return round(100 (s - 1000) * 0.15, 2) else: return round(220 (s - 1800) * 0.20, 2) pytest.mark.parametrize(a,b,c,exp_sales,exp_comm, [ (10, 10, 10, 1000, 100.00), (10, 10, 11, 1025, 103.75), (19, 4, 33, 1800, 220.00), (19, 5, 32, 1805, 221.00), ]) def test_commission(a, b, c, exp_sales, exp_comm): s calc_sales(a, b, c) assert s exp_sales assert calc_commission(s) pytest.approx(exp_comm, abs0.01)把用例表拆成数据行塞进参数化装饰器几十条用例几秒钟就能跑完。但注意自动化脚本的价值是快速回归不是帮你“发现”测试用例。用例设计没过关脚本跑得再快也只是把错误预期重复执行一遍。5.2 从佣金问题迁移到真实计费业务佣金问题里的分段提成和真实业务中的阶梯计价几乎是同一个模型。电商的满减、快递的运费模板、保险行业的佣金结算、积分兑换规则底层都是“输入参数→计算金额→输出结果”。从这道练习里沉淀下来的测试资产可以通用需求澄清清单金额精度、边界归属、非法输入处理方式。用例设计模板正常功能、单变量边界、组合边界、非法输入、精度校验。缺陷分析套路先确认用例预期对不对再确认开发实现最后确认需求本身是否清晰。这套东西我已经在很多真实项目里复用佣金问题练熟了遇到复杂一点的阶梯折扣也不慌。区别在于真实业务的规则可能嵌套更多档位、更多维度但测试设计的底层逻辑不会变。5.3 这条练习题怎么继续扩展如果想再进阶一点还可以给佣金问题加几个需求按销售员累计月度佣金计算个税、支持批量导入销售数据、并发提交时防止超卖等。每加一个需求边界条件就多一层测试设计的复杂度就上来了。我自己带新人时习惯让新人先独立设计一遍我再拿经典用例做对照讲评。大多数情况下新人的用例里真正缺的不是“数量够不够”而是对“销售额1000边界”和“非法输入处理预期”这两个关键点的把握。我个人做这道题最大的体会是佣金问题的难点从来不在计算本身而在测试设计者对“假设”的管理。你假设了数量不会超界、假设了金额永远精确到分、假设了用户不会输入负数这些假设往往就是线上事故的源头。所以不管练多少遍我都会提醒自己预期结果一定要独立手算边界用例一定要标出可达值需求没说清的地方一定要落到文档里变成待确认问题。真正好的测试用例不是数量多而是边界全、预期结果经得起推敲。每次带新人重新做这套练习我都能从对方的用例里看出他思考问题的方式这也是这道题能一直流传下来的原因。