我做了十来年测试,带过不少新人,也评审过很多团队的测试用例。说句实在话,大部分用例写得都有点浪费:要么是照着需求文档把功能描述抄了一遍,要么是写完以后自己也不想再看第二遍,更别说让别的同事拿着去执行。今天聊一聊怎么把测试用例从“凑数交差”写到“真能发现问题”,把这些年实际用下来的思路、模板、方法和踩过的坑都摊开讲一遍。
先说清楚一点:测试用例不是什么高深的东西,它的本质就是“把怎么测某个功能这件事,从人的脑子里搬到纸面上”。但恰恰是这个简单的迁移过程,绝大部分人都做得不够好。这篇文章适合刚入行的测试新人,也适合带团队的技术负责人,包括写自动化脚本的工程师——底层逻辑都是一样的,区别只是在表达形式。
1. 测试用例不是写废话:先搞清楚它到底解决什么问题
1.1 测试用例的三个核心价值
很多团队把测试用例当成“给领导看的文档”,写完就束之高阁,这是典型的本末倒置。我理解下来,测试用例的价值集中在三个层面,缺一个都值得你重新审视自己的写法。
第一层是可重复性。一个功能今天测完了,三个月后改了个需求,谁来回归?如果全部依赖测试员的记忆和临时发挥,人员一变动,整个模块的测试经验就全断了。用例落到文档或者管理系统里,任何一个人拿过来就能执行,这就是团队知识的沉淀。我见过最典型的案例:某公司一个核心系统的测试只有一个人懂,这人一离职,后面接手的同事对着系统两眼一抹黑,只能重新摸索。如果当时用例写得足够好,交接成本至少能降一半。
第二层是可衡量性。有了用例,你才能回答“这个版本测了多少条、通过了多少、失败了多少、还有多少没跑”。没有用例,测试范围就是一笔糊涂账,到上线前你根本说不清“到底测完没有”。覆盖率、进度、风险评估,所有这些管理动作全都建立在用例的基础之上。很多线上事故,追根溯源就是“当时没人测过那条路径”,为什么没人测?因为用例里根本没有。
第三层是可改进性。用例写得好不好,直接反映了你对需求的理解深不深。我在评审用例的时候经常发现,产品、开发、测试坐在一起过一遍用例,很多需求的歧义、设计的漏洞,在写代码之前就暴露了。这个价值比用例本身还大,等于用最低的成本做了一次早期需求验证。
1.2 什么时候可以不写用例
我知道有些敏捷团队会喊“我们不用写用例,直接探索性测试”。这句话对了一半。探索性测试适合的场景是:需求极不稳定、原型随便改、没人知道用户到底会怎么用的创新功能。这种情况下写一堆步骤详细的用例,确实过两天就作废了,纯属浪费精力。
但更多时候,业务系统、核心流程、复杂的逻辑判断,不写用例就是在裸奔。当年我负责电商支付模块的测试,那种场景你试试不写用例?一个支付流程横跨订单、优惠、库存、渠道网关、对账系统,十几个模块联动,不靠用例把每个分支覆盖清楚,线上出问题就是资损,没有任何人担得起。
所以我自己的判断标准很简单:代码会反复回归、逻辑有分支、多人需要协作的功能,必须写用例;一次性演示、纯探索验证、用过即弃的脚本,可以不写。用不用例是个成本决策,不是态度问题,但成本决策的前提是你真的理解不写的代价。
注意:很多人觉得“小需求不用写用例,我脑子记得住”。我的经验是,越小的需求越容易出低级事故,因为你觉得它简单,就不会认真想边界。一个“改个文案”的需求都有可能牵扯到不同端的同步问题,一条用例的成本远低于一次线上事故。
2. 一个标准测试用例的组成拆解
2.1 用例编号、标题和模块归属
写用例第一步,是给每条用例一个唯一的身份标识。我习惯的编号规则是“模块缩写+下划线+三位递增序号”,比如PAY_001、ORDER_002、LOGIN_003。这个编号一旦确定就不要变,后面报缺陷引用它的时候特别方便。你想象一个场景:提测群里开发说“我先改一下支付的问题”,你回一句“对应的用例是 PAY_013,你复现一下”,沟通成本会低很多。
标题怎么写是个大学问。我见过海量用例标题是“验证登录功能”“验证支付流程”,这种写法等于没写。标题应该描述被测行为+操作对象+预期结果,比如“使用正确密码登录成功后跳转首页并显示用户名”。拿到标题就能大概知道这条用例的验证点,在用例列表里扫一眼就能定位问题,而不是必须点进去看步骤才知道这条用例在干什么。
模块归属字段也同样重要,它决定了缺陷统计的口径。很多管理工具里模块树没有提前规划好,测试人员随意填,最后出来的缺陷分布报表根本没法看。我的建议是,用例的模块归属和后续缺陷报告的模块分类保持完全一致,这样你才能回答“哪个模块质量最差”这种管理问题。
2.2 前置条件、测试步骤、预期结果怎么写才有用
展开讲几个核心字段,这些字段是任何测试用例管理工具里都必须有的,包括在 Excel 里自己维护也一样。
前置条件:用例执行前必须满足的状态。比如“用户已登录且账户余额大于100元”“测试环境已部署最新版本”“测试账号具备管理员权限”。很多人图省事不写前置条件,或者写一句“默认环境”,结果执行到一半发现环境不对、数据不够,整条用例作废。前置条件写得越具体,别人执行起来越顺畅。
测试步骤:从操作者的视角写,编号清晰的步骤序列。这里最关键的规范是:每个步骤只描述一个动作。比如“输入手机号”是第一步,“点击获取验证码”是第二步,不要写成“输入手机号并点击获取验证码”。如果一条用例执行失败,多动作混合的步骤你根本定位不到是哪一步出了问题。另外步骤里的输入数据要写具体的值,不要写“输入随机手机号”,执行的人不知道填什么。
预期结果:必须可验证、可判断。不要写“系统正常”“页面显示正确”“报错提示”,这些全是废话。要写成“页面右上角显示用户名‘张三’,并跳转到首页”“弹出提示框,内容为‘验证码已发送至尾号1234的手机号’”“订单状态变为‘已支付’,数据库支付流水表新增一条记录”。模糊的预期结果是测试用例最大的浪费来源,因为执行者根本无法判断用例是通过还是失败。
实际记录的时候,还会有一个“实际结果”字段,这是执行阶段才填的,设计用例的时候不用管。
2.3 优先级和用例层级
用例一定要分优先级,业界通用的做法是 P0/P1/P2。
- P0:核心流程,主路径,不通过就不能上线。比如登录功能、支付功能、数据存储。
- P1:重要功能,主流使用场景的辅助路径。比如搜索过滤、列表分页、消息提醒。
- P2:边缘场景、异常分支、兼容性验证。比如输入超长字符、弱网环境、空列表操作。
优先级的意义不是摆设,它是给回归测试排顺序的。每次发版,测试时间就那么点,P0 先跑,P1 排后,P2 最后时间不够就砍掉。没有优先级,回归的时候只能眉毛胡子一把抓,时间不够了就随机砍用例,砍掉的偏偏是最重要的用例,这种事情我见过太多了。
另外新人在分配优先级的时候容易犯一个错误:觉得所有用例都重要,全给了 P0。这等于没分级。我的经验是 P0 用例最好控制在总用例数的 20% 以内,P1 占 50%,P2 占 30%,这样回归的时候才有真正的抓手。
3. 从需求到用例:核心设计方法实操
3.1 等价类划分:把无穷输入变成有限用例
等价类划分是基础中的基础,核心思想是:把输入数据按“是否会产生相同结果”分组,每组选一个代表值测试就够了,不需要穷举。
举例来说,手机号输入框的校验规则是“11位数字,以1开头”。这时候所有可能的输入可以分成两类:有效等价类(符合条件的手机号)和无效等价类(不符合条件的各种情况)。有效等价类里随便取一个正常手机号测一次就行;无效等价类里则要把“位数不是11位”“包含字母”“不以1开头”这些情况各测一次。这样一个输入框,四条用例就覆盖了全部输入可能性。
有人会问,为什么无效等价类要多测几种?因为无效输入的处理路径存储不同的分支,比如位数不对可能走长度校验,包含字母可能走字符校验,不以1开头可能走号段校验,这些分支的处理逻辑各自独立,都得覆盖到。
等价类划分的意义在于告诉测试员:你的精力是有限的,要花在代表值上,而不是穷举上。如果一个输入框把每个可能的值都测一遍,你的用例量会爆炸,而且大部分是重复劳动。
3.2 边界值分析:边界最容易出 bug
边界值分析是等价类的最佳搭档。为什么单拎出来说?因为经验告诉我们,bug 最密集的区域往往在输入范围的边缘,而不是中间。道理也很简单:开发写判断条件的时候,最容易写错的就是边界,比如把>=写成>,把<写成<=,或者把“18到60岁”写成“18以上60以下”导致刚好 60 岁被拒绝。
举个例子,年龄输入框限制 18 到 60 岁。边界值分析要求你测这六个值:17、18、19、59、60、61。边界值本身是 18 和 60,边界值内侧是 19 和 59,边界值外侧是 17 和 61。左右两侧的值每个都得测,一处都不能省。
有时候还要考虑边界值的边界,比如日期输入框要求“2025年1月1日至2025年12月31日”,那么边界值就包括 2024-12-31、2025-01-01、2025-01-02、2025-12-30、2025-12-31、2026-01-01 这六个日期。
我做过一次简单的统计,在一个有数十个输入框的业务系统里,通过边界值分析发现的缺陷占了总缺陷数量的将近三成。这不是巧合,边界问题就是高频问题。所有输入框、所有长度限制、所有范围限制,都值得你认真把边界值列出来。
3.3 场景法:覆盖用户真实的操作路径
等价类和边界值解决的是“单一输入”的验证问题,但用户在实际使用中从来不会只操作一个输入框。场景法的核心是从用户的角度,把功能的主要业务路径串起来,验证的是多个步骤、多个模块联动时的协调性。
以一个典型的网购下单流程为例:浏览商品 → 加入购物车 → 结算 → 填写收货地址 → 选择支付方式 → 支付成功 → 生成订单 → 收到通知。这个流程里每一步都有分支:购物车为空能不能结算、地址没填系统怎么提示、支付超时会不会自动取消订单、库存不足会不会拦截支付。主成功路径必须测,关键异常路径也必须测,把每一条重要的路径都变成一个完整场景。
场景法特别适合发现接口之间传递的问题。单测一个页面的时候什么都正常,但把“加入购物车 → 结算 → 支付”整条链路串起来跑,就会发现购物车里的商品价格和结算页不一致、支付成功后订单状态没同步、通知消息发重复了——这些都是模块联动才会暴露的问题。
实操上,我建议先画一张简单的流程草图(不进文档管理工具,就是自己手写或者用画图工具),把主路径和异常分支都标出来,再顺着每一条路径写场景用例。有了这张图,你写出来的用例就不是零散的,而是有结构的。
3.4 判定表与状态迁移:组合逻辑的克星
当业务流程存在“多个条件组合决定一个结果”的情况时,等价类和场景法都会失效,这时候要用判定表。举一个典型的例子:优惠券发放规则是“用户为注册7天内新用户、订单金额满100元、使用指定支付方式,三个条件同时满足才发券”。三个条件每个都有“满足/不满足”两种状态,组合起来共有 2×2×2=8 种情况。把所有组合列成一张表,逐条设计用例,保证每个组合都覆盖到,这就是判定表。
判定表的优势在于,它能防止你把“条件考虑不全”当成“测试完成”。我见过很多测试员在设计条件组合时靠拍脑袋,“我猜这几个条件影响结果”,结果漏掉了某个条件组合,上线后正好命中。判定表迫着你把逻辑穷举一遍,哪怕你不跑每一条组合,至少你能看到全部组合是什么样。
状态迁移法适合状态多、状态转换规则复杂的对象。最常见的例子是工单处理:新建 → 处理中 → 已解决 → 已关闭,还可以有“重新打开”“挂起”等状态。每一种状态能触发什么操作、不能触发什么操作,从状态 A 能不能跳到状态 C,这些规则如果靠脑子记忆,迟早会漏。把状态图列出来,为每条状态迁移路径设计用例,才能做到不重不漏。
这两个方法平时用得相对少,但当系统复杂度上来的时候,它们往往是你发现漏测的最有力武器。
3.5 错误推测法:经验主义也不丢人
经过前面几个方法,正常场景和大部分异常场景都覆盖了,但有些缺陷还是测不出来。这时候就要靠错误推测法了。说直白点,就是“结合以往经验猜哪里容易出问题”。
常见的错误推测案例包括:空数据时点删除按钮、列表为空时点击搜索、连续快速双击提交按钮、断网时点支付、弱网环境上传图片、输入超长字符串、复制带有特殊字符的内容粘贴到输入框、切换页面时刷新操作,等等。这些场景并没有在需求文档里明确定义,但老测试员知道它们就是高频翻车点。
有人问,错误推测法是不是全靠猜?其实不是。它的基础是过往的缺陷记录、线上事故、用户反馈。我自己的习惯是,维护一个“风险场景清单”,每发现一个新的高危场景就往里加,写用例的时候翻一遍。日积月累,这个清单的价值会超过任何一个设计方法。
错误推测法和前几种方法不是替代关系,而是叠加关系。先用等价类划分和边界值分析法覆盖常规输入,再用场景法覆盖业务流程,用判定表覆盖条件组合,最后用错误推测法补上经验性的盲区。这五层叠加起来,用例的覆盖度才真正高得起来。
4. 测试用例的评审、执行与维护
4.1 用例评审怎么开才有效率
用例写完之后,一定要评审。但很多团队的评审会开得很痛苦:几十上百条用例一条条念过去,念的人犯困,听的人走神,最后啥结论也没有。
我的做法是,评审会分层次过:一验需求覆盖,二验逻辑正确,三验用例本身的可执行性。需求覆盖那一步,最好拉产品参加,把需求点列成清单,逐条和用例对上号。对不上的要么遗漏了需求,要么用例写了需求里没有的内容。这个环节不需要逐条读用例,只需要对着需求核对用例编号列表。逻辑正确那一步,需要测试组内部最有经验的同事把关,重点看条件组合和边界值有没有漏。可执行性那一步,是看步骤写得到不到位、预期结果清不清楚,可以由执行用例的同事来提意见,因为他们才是最终拿着用例跑的人。
评审会特别要注意的一点是:提前把用例发给参与者,让大家带着问题来开会,而不是会上才开始看。我见过太多评审会从“我念一遍用例”开始,到“你念完了我们结束”结束,整个过程没有任何信息量。
4.2 用例和缺陷的关联:可追溯性
测试执行阶段,用例和缺陷必须能互相追溯。一条缺陷报出来,要能关联到它暴露的是哪一条用例;一条用例执行失败,要能快速找到它对应的缺陷。没有可追溯性,你根本说不清“这个版本的问题集中在哪个模块,是哪一类用例更容易发现缺陷”。
实操层面,我在缺陷报告里必填两个字段:复现步骤和关联用例编号。复现步骤帮助开发定位,关联用例编号帮助测试反向统计。统计出来的数据有什么价值?如果只有少数几条用例反复报出缺陷,说明这几条用例覆盖的区域是高风险区;如果绝大多数缺陷都不是用例执行出来的,那说明用例设计有问题才覆盖度不够高。
另外,每次版本结束做复盘的时候,我会把“新增用例命中缺陷”的比率拉出来看一眼。如果新增用例全部没发现问题,可能说明用例设计偏离了真实的变更点,那下次测试设计的时候就要换个思路。
4.3 用例维护:什么时候更新、怎么更新
用例不是写完就一劳永逸的东西,它和代码一样需要维护。我归结了三个必须维护用例的时机。
第一个时机是需求变更时。需求一变,用例必须同步变。哪怕只是改了一个按钮的文案,用例里的预期结果也得跟着改,否则下次执行的时候,执行者会对着一个已经不存在的按钮发呆。第二个时机是缺陷修复后。一个缺陷被修复,说明之前那条用例设计的验证逻辑可能不完整,要么补一条针对该缺陷的回归用例,要么把原有用例的步骤细化。第三个时机是定期全面梳理,我一般以季度为单位,把整个模块的用例通读一遍,删掉过时废弃的用例,合并重复的用例,更新环境相关的信息。
维护的具体操作上,我的习惯是:在用例变更的时候留一行“变更日志”,记录“什么时候、改了什么、为什么改”。这个习惯在复盘和排查历史问题的时候非常有用,不然一条用例改过三次之后,你根本不知道当时为什么把预期结果从 A 改成了 B。
注意:很多团队的用例文档半年不更新,里面的按钮名都是旧版本的,环境地址还是测试内网老 IP。这种用例的执行价值基本为零,甚至会产生负价值——你照着一份过时用例执行,报出来的缺陷开发大概率会回复“这个界面已经改版了,你是在老版本上测的吧”。
5. 新手常踩的坑与我的实操心得
5.1 六个高频问题速查
我在面试测试工程师和带新人的时候,会特别观察他们写的用例风格。下面这六类问题,是出现频率最高的,每个问题都附了处理建议,可以对照自己的用例检查。
| 常见问题 | 具体表现 | 处理建议 |
|---|---|---|
| 用例冗长无重点 | 一个功能写了几百条用例,回归根本跑不完 | 用爱人和场景法先理清结构,再用优先级分级聚焦高价值用例 |
| 用例过粗 | 一条用例步骤里包含了十几个操作动作 | 一条用例只验证一个场景,步骤按操作序列拆分到最小动作 |
| 预期结果模糊 | “系统正常”“页面显示正确”“报错” | 明确“出现什么提示”“跳转到哪个页面”“数据变成什么状态” |
| 前置条件缺失 | 执行到一半发现没有对应账号或环境 | 写明测试数据、环境版本、账号角色和权限 |
| 边界与异常覆盖不足 | 只测正常值,所有用例都是合法输入 | 每次设计完检查一遍:边界值、空值、超长、重复操作、断网 |
| 用例从不更新 | 需求改了三轮,用例还是最初版本 | 需求变更和缺陷修复后同步维护用例,季度全量梳理一次 |
5.2 我个人的几个具体习惯
最后分享几个实操习惯,这些东西没写在任何教材里,都是实践中打磨出来的。
第一,写用例之前先画“测试设计草图”。这个草图不用进管理系统,就是自己梳理用。我通常用白纸或者绘图工具,把功能的主流程、分支、异常分支先捋一遍,标注哪些点要重点覆盖,然后才往用例表格里填。直接开空白的用例表格硬写,写出来的用例往往是零散的、跳跃的。
第二,预期结果尽量量化。能用“出现提示‘XX’”“跳转到 XX 页”“数据库字段 XX 变为 YY”这种描述,就绝不用“正常”“正确”“成功”这种笼统的词。量化的预期结果不仅让执行判断变得容易,而且在自动化测试的时候可以直接转成断言,一份用例两种用途。
第三,用例写完后,自己先当“执行者”过一遍。我会把每条用例的步骤在脑子里模拟执行一遍,如果发现某一步看不懂、不知道怎么操作、不知道要准备什么数据,说明这条用例写得还不够清楚。凡是自己都执行不下去的用例,别人更执行不下去。
写了十来年测试用例,我最深的体会是:好的用例不是数量堆出来的,而是把业务逻辑理解透之后,用最经济的手段把风险覆盖住。你不需要每一条都写得天花乱坠,但你得保证每条用例拎出来,别人能看懂、能执行、能验证。能做到这三点,测试用例就已经算合格了;如果能顺手把边界和异常补扎实,那就是一份高质量的测试用例。