
简介这份Word文档围绕软件测试用例的经典实例展开面向软件测试初学者、测试工程师及需要系统梳理用例设计方法的读者帮助其理解如何把测试理论落到具体案例中。文档依次整理优质测试用例应包含的要素并给出B/S登录功能的黑盒测试用例以及等价类划分法中的三角形判定实例、边界值分析法中的NextDate函数实例还涉及错误推测法、因果图法与判定表驱动法等常见设计思路覆盖功能校验、容错性、安全校验等典型场景。压缩包共1个doc文件约329KB篇幅紧凑便于检索和打印查阅。已有4782人学习说明其案例选型具有一定参考价值。读者可从中获得可直接借鉴的用例模板、场景拆解方式和预期结果编写思路适合作为测试用例设计练习与面试复习的对照材料。1. 到底什么是测试用例一份写给接手者的说明书拿到一个陌生系统让你点一下登录框看看账号密码输错会怎样任何人都会觉得这活儿简单。可三天后换一个人来做同一件事他填的数据不一样、点的地方不一样得出的结论自然也不一样——这次验证就等于白做。测试用例解决的正是这件事它把「怎么操作、输入什么、应该看到什么」提前写死变成一份换谁照着做都能复现的记录。通俗地说它像菜谱里的「盐 3 克、中火 5 分钟」不是写给已经会做菜的人看的而是写给任何一个接手的人看的。这个类比放到软件里更明显一个功能今天测过下个月改了两行代码如果没有可复现的用例你只能凭记忆重来一遍结果好是运气好出问题是迟早的事。很多人第一次翻测试用例的经典实例、例子看到的是一张张表格觉得不过是走流程的文档真正跟过几轮迭代才明白那些表格背后藏着的是一套「怎么用有限的几次尝试去覆盖几乎无限的输入」的思路。2. 一条用例该写清什么十二项信息背后的分工一份完整用例通常要写十二项东西软件或项目名称、版本号、功能模块名、用例的简单描述、参考信息、用例之间的依赖关系、前置条件、用例编号、步骤号与操作步骤和测试数据、预期结果与实际结果、开发人员与测试人员、执行日期。十二项一列出来绝大多数人的第一反应是「这也太啰嗦了」。可这十二项不是拍脑袋凑的它们各自回答一个不同的问题按用途能归成四组这份用例是谁、从哪儿来、要在什么状态下跑、跑完拿什么判断对错。缺任何一组这条用例的可用性都会掉一个档次。分组包含的字段回答的问题身份组项目名称、版本、模块名、用例编号、用例名称这条用例是什么、属于谁来源组简单描述、参考信息、依赖关系它为什么存在、依据是什么上下文组前置条件跑它之前必须满足什么判定组步骤、测试数据、预期结果、实际结果、人员、执行日期怎么跑、拿什么算通过2.1 身份组编号和版本不是形式主义用例编号看似最没技术含量实际最影响协作。常见的写法是「软件名称简写-功能块简写-序号」比如一个订单系统里的登录模块编号可以写成ORD-LOGIN-001。这个规则的价值在于排序和检索当你在缺陷管理系统里搜ORD-LOGIN相关的用例会整整齐齐排在一起而不是散落成一堆「测试登录1」「测试登录2改」「测试登录-最终版」。命名一旦失控半年后连写用例的人自己都分不清哪条还有效。版本号这一项更容易被忽略因为大部分人潜意识里觉得「功能没变写什么版本」。可功能恰恰是最容易悄悄变的东西。同一条登录用例在某个内部版本里密码错三次锁定账号在另一个版本里改成错五次——用例不带版本三个月后回看这条记录你根本说不清当时测的是哪套规则一切归因都变成玄学。项目名称和功能模块名的作用类似是给用例划定边界一条用例只应该属于一个模块、一个明确的项目跨模块的大杂烩用例几乎没法维护。用例名称和简单描述经常被写成同一个东西其实分工不同。名称是标签要短、要能一眼扫过去就知道测什么比如「只填用户名不填密码」描述是目的说明讲清这条用例想验证哪条规则比如「验证密码为空时的必填校验提示」。名称给检索用描述给理解用两者合成一句就会两头不讨好。参考信息则是给未来的自己留的线索需求说明书的哪一节、设计稿的哪个编号、对应的缺陷单号。这类信息平时用不上一旦要追溯「这条用例当初凭什么这么写」它就是唯一的证据。2.2 上下文组前置条件与依赖关系最容易翻车的两栏前置条件写的是「执行这条用例之前必须成立的事」比如对数据库有访问权限、测试账号已经注册好、当前停留在登录页面。这一项最常见的写法是空着理由往往是「这不是明摆着的吗」。问题在于写的人眼里的明摆着和三天后接手的人眼里的明摆着根本不是同一件事。一个人本地环境里早就存着登录态另一个人从干净环境进来第一步就卡住了最后得出的结论是「用例有问题」而不是「前置条件没写」。依赖关系比前置条件更微妙它描述的是用例之间的顺序耦合。拿登录功能来说那条「登录成功」的用例本身就依赖「用户名能正常录入」和「密码能正常录入」这两条先跑通。如果前两条挂了第三条即便执行了得到的结果也没有任何参考价值。这时候正确的处理是把它标记成「阻塞」而不是「失败」——阻塞意味着前提没满足、结论不可信失败意味着功能确实有问题。这两者混在一起缺陷统计就会彻底失真团队会花大量时间去修一个根本不存在的 bug。依赖关系写清楚还有一个隐性好处它逼着你把用例之间的逻辑顺序想明白。一条用例依赖另一条说明它们在业务上是串联的串联的地方往往就是缺陷最容易钻出来的地方。2.3 判定组预期结果是整条用例的锚点十二项里预期结果是唯一不能含糊的一项。原文里特意强调它是「最重要的」这个判断很准一条用例如果预期结果写得模棱两可前面十一项写得再漂亮也白搭因为执行的人根本无法判断到底通没通过。预期结果最典型的失败写法是「显示正常」「登录成功」「提示错误」。这三个词看着像结论实际上是三种主观感受。「显示正常」——正常的标准是什么页面元素齐全算正常还是布局没乱算正常「提示错误」——提示的是哪一句话弹窗还是行内红字这些不写明两个执行者能得出两个结论然后花半小时争论到底是谁看错了。可判定的写法应该长这样「提示文案为『需要输入密码』且停留在登录页不跳转」。有具体的文案、有具体的页面状态任何人执行都能给出同一个答案。实际结果这一项在老式文档里要手工填现在多数团队有缺陷管理工具可以直接省略让工具去关联。但「省略」的前提是工具真的在用而不是既没有工具也没填表最后谁也不知道这条用例上次跑出来是什么样。开发人员和测试人员这两栏看着像流程要求实际作用是定责和沟通路径出问题时知道找谁复测时知道谁验的。执行日期则是给结果加时间戳一个两个月前的「通过」和昨天的「通过」可信度完全不是一回事。把十二项字段落到纸面上大概长这样# 一条登录用例的字段结构仅示意各字段的用途 case { project: 某内部系统, # 软件或项目名称 version: 内部版本号 v0.9.3, # 版本缺了它用例只是一份草稿 module: 登录, # 功能模块名 case_id: SYS-LOGIN-007, # 编号系统简写-模块简写-序号 title: 只填用户名不填密码, # 用例名称短标签 desc: 验证密码为空时的必填校验, # 用例描述讲目的 ref: 需求说明书 3.2 节, # 参考信息便于追溯 depends_on: [SYS-LOGIN-002], # 依赖用户名录入先要能通过 precondition: 已打开登录页测试账号已注册, # 前置条件 steps: [ (1, 用户名输入框填入 test, test), (2, 密码框留空, ), (3, 点击登录按钮, ), ], expected: 提示文案为『需要输入密码』停留在登录页, # 预期结果必须可判定 }这段结构里没有一行是多余的depends_on决定这条用例失败时该记阻塞还是记缺陷precondition决定换台机器还能不能跑expected里带了具体文案和页面状态所以任何人执行都能得到同一个结论。字段名可以随团队习惯改但这几类信息一个都不能少。3. 用例从哪里长出来黑盒视角下的场景切分与等价类有了字段结构下一个问题是内容从哪儿来。总不能对着一个输入框把所有可能的字符串都试一遍——那是无穷多个。测试用例设计方法要解决的就是怎么从无穷里挑出有限且有代表性的那几次。这一章讲三种最常用的切法按场景切、按等价类切、按边界切。它们都属于黑盒思路也就是不关心代码内部怎么写的只看输入和输出之间的对应关系。3.1 先按场景切登录功能的十条用例黑盒测试的第一步通常不是算数据而是把用户真实会走的路径列出来。一个 B/S 结构的登录页面功能描述无非四句打开地址要显示登录界面输入用户名密码后系统自动校验并给出提示任一信息没填要给提示连续三次没通过验证时关闭浏览器。四句话听着简单展开成场景却有十来个。用例 ID场景操作预期结果TC1初始页面显示打开地址进入登录页页面元素完整与详细设计一致TC2用户名录入验证输入已存在的用户 test输入成功TC3用户名容错性输入超长字符串到达长度上限时系统拒绝继续输入TC4密码录入输入与用户名对应的密码输入成功TC5登录成功依赖 TC2、TC4点击登录进入系统页面TC6用户名密码都为空直接点击登录提示请检查用户名和密码的输入是否正确TC7只填用户名密码留空点击登录提示需要输入密码TC8密码错误密码与用户名不匹配提示错误的密码TC9用户名不存在填入不存在的用户名提示用户名不存在TC10安全校验连续三次登录失败提示您没有使用该系统的权限请与管理员联系这张表最值得看的是它的结构而不是内容。TC1 到 TC4 是「零件级」的验证只关心单个输入框能不能正常接收数据TC5 开始才是「整机级」的验证关心组合起来之后的业务结果TC6 到 TC9 是四种不同的错误分支每一种对应一句不同的提示文案TC10 是状态累积的场景前九条都通过也不代表它能通过因为它依赖的是「失败次数」这个跨请求的状态。按场景切的好处是直观任何人拿到这张表都知道该点哪里。它的局限也很明显场景是人想出来的想漏了就真漏了。一个输入框到底该输多长、该不该支持特殊字符、空格算不算有效输入靠拍脑袋很难穷尽。这就是后面几种方法要补的位。顺带说一句表里那条「假设用户使用某个早期版本的浏览器」在当年是必要信息放到现在就该换成一段明确的浏览器与分辨率范围。用例里的环境描述从来不是装饰它决定了这条用例在别人的机器上还能不能复现。3.2 等价类划分把无限输入塞进几个抽屉等价类划分的思路用一个类比就清楚了一个柜子有无数个格子但你不需要每个格子都翻一遍才能确定里面有没有东西只要按「可能有」和「不可能有」分成几类每类抽查一个就行。测试里的等价类就是这个意思——把所有可能的输入划分成若干个子集同一个子集里的数据对程序而言行为一致那么每个子集挑一个代表就够了。经典例子是三角形判定程序接收三个整数 a、b、c 作为三条边长判断能构成一般三角形、等腰三角形还是等边三角形。输入条件看着只有三个数隐含的要求却有一串必须是整数、必须是三个数、必须非零、必须为正数、两边之和必须大于第三边、等腰和等边各有自己的条件。把这些条件列成表就得到了有效等价类和无效等价类两个方向。有效等价类是说「这些输入应该被正常处理」对应的用例是abc覆盖的等价类345整数、三数、非零、正数、两边和大于第三边、三边不等445上述全部外加「两边相等」455上述全部外加「另两边相等」545上述全部外加「第三组两边相等」444上述全部外加「三边相等」这五条用例的设计意图非常清晰前四条把「等腰」的三种位置关系各测一遍因为很多实现只判断了ab而漏掉bc这是个高频出错点第五条单独覆盖等边。它们共同覆盖了所有有效条件一条都没浪费。无效等价类才是真正考验功力的地方。规则是一条用例只违反一个条件其余条件全部保持有效。比如测「非整数」时三个数里只放一个 4.5另外两个仍是正常的 4 和 5测「非正数」时只放一个 0 或 -1测「两边之和不大于第三边」时只让 1、2、5 这种组合出现。如果把「非整数」和「非正数」放进同一条用例程序报错时你根本不知道是哪个条件触发的这条用例就白跑了。这里有个初学者最容易踩的坑以为等价类划分就是「随便挑个代表」。实际上代表挑得对不对取决于你把条件拆得够不够细。拆条件的过程本质上是回头读需求的过程——需求里每一句「必须」「只能」「不少于」都是一个等价类的边界。3.3 边界值分析错误最爱蹲在临界点上如果等价类是在抽屉里抽查边界值分析就是专门盯着抽屉的边缘看。原因很朴素程序员写判断时最容易在和之间搞错而这类错误只会在临界值附近暴露。你输入 15 和输入 16程序表现都正常输入 31 和 32问题就出来了。典型的例子是 NextDate 函数输入月、日、年输出下一天的日期。隐含的取值约定是月份 1 到 12、日期 1 到 31、年份 1912 到 2050。边界值分析的做法是对每个变量各取「下界、下界加一、上界减一、上界、略微越界」这几个点其余变量保持正常值不动。变量取点示例输入观察什么year1911 / 1912 / 19136, 15, 1911 起年份下界附近是否被正确处理year1975 / 2049 / 2050 / 20516, 15, 对应年份年份上界 2050 及其越界day-1 / 1 / 2 / 30 / 31 / 326, 对应日期, 2001日期上下界含月末跨月month-1 / 1 / 2 / 11 / 12 / 13对应月份, 15, 2001月份上下界含年末跨年这张表里最容易被忽略的不是越界值而是「上界减一」这种看着平平无奇的点。日期取 30 和 31对大部分月份没区别但 6 月只有 30 天输入 6 月 31 日时程序该怎么反应就是一条必须明确的规则——是报错还是自动进位到 7 月 1 日需求里不写实现就靠猜测试也就只能靠猜。边界值分析和等价类划分经常被当成两件事其实它们是配套的等价类告诉你「哪些范围算一类」边界值告诉你「在这个范围的哪几个点上重点检查」。一个抽屉抽一个代表是等价类把抽屉的两条边摸一遍是边界值。两套一起用覆盖面才立得住。4. 输入之间互相牵连时因果图、判定表与错误推测前三节的方法有个共同前提各个输入之间相对独立可以分别处理。可现实里的业务逻辑经常不是这样——投一枚硬币和按一个按钮单独看都没问题组合起来才决定该不该出货、该不该找零。这时候光靠列场景已经不够用了得换个能表达「条件组合」的工具。4.1 因果图自动售货机里那盏红灯经典例子是一台卖 5 角钱饮料的自动售货机。规格说明是这样的投入 5 角或 1 元硬币按下橙汁或啤酒按钮相应饮料送出如果没有零钱可找一盏「零钱找完」的红灯亮起此时投入 1 元并按按钮饮料不出、1 元退回如果有零钱红灯灭送饮料的同时退 5 角。把这段话拆成因果原因有五个有零钱可找、投入 1 元、投入 5 角、按橙汁按钮、按啤酒按钮。结果也有五个红灯亮、退 1 元、退 5 角、出橙汁、出啤酒。但这五对五之间不是简单的一一对应中间还夹着几层状态投了 1 元又按了按钮、按的是橙汁或啤酒之一、应该找 5 角且确实有零钱、钱已付清。原文把这些叫中间结点编号为 11 到 14。给中间结点单独编号是因果图最关键的一步。它把「投入 1 元」和「按下按钮」这两个本来独立的动作合并成一个有业务含义的状态「钱付了、货选了」后面所有判断都基于这个状态而不是原始动作。这跟写代码时先算中间变量再判断是一个道理只不过这里是画在纸上。画完因果图还不算完它本身没法直接执行。因果图真正的价值是当跳板把图上的逻辑关系转成判定表判定表才是能逐列执行的测试依据。很多人卡在这一步画完图觉得事情做完了结果图躺在文档里没人看。4.2 判定表把八条规则摊平再压回去判定表的结构很固定上半部分是条件桩列出所有要判断的条件下半部分是动作桩列出所有可能的动作每一列是一条规则代表一种条件组合。举个更直白的例子某设备规则写着「功率大于 50 马力的机器、维修记录不全或已运行 10 年以上的机器应给予优先的维修处理」。三个条件每个两种取值规则数就是 2×2×28 条一条不多一条不少。填表时从最后一行往上填先按 Y N Y N 交替再按 Y Y N N 交替最后按一半一半交替八列就填满了。这个填法看着机械作用是保证不漏不重。填完之后会发现八列里有些列的结果完全一样而且它们的区别只在于某个条件取值是 Y 还是 N——也就是说这个条件对最终动作根本没影响。这时候就可以把这几列合并该条件项写成「-」表示「取什么都行」。原始八列合并下来通常能压到五六列。判定表最容易暴露的问题是需求文字本身的歧义。上面那句「功率大于 50 马力的机器、维修记录不全或已运行 10 年以上的机器」那个「或」到底管到哪儿是「功率大于 50」和「记录不全或运行超 10 年」两个条件取或还是三个条件并列取或不同的读法画出来的判定表完全不同覆盖的用例数量也差好几倍。把表摊在需求方对方面前指着某一列问「这种情况你们希望优先处理吗」比反复读那段话有效得多。这也是判定表最被低估的作用它不只是设计用例的工具还是澄清需求的工具。4.3 错误推测法没有公式只有一份「容易坏在哪」的清单前面几种方法都有明确的推导步骤错误推测法没有。它靠的是经验列出这个类型的程序历史上最容易出错的地方然后针对性地设计用例。一个对线性表排序的程序凭经验就该想到这几处输入表为空表表中只有一个元素输入表已经排好序输入表完全逆序表中部分或全部元素相同。这五条的共同点是「边界形态」——空表会让循环一次都不执行单元素会让某些交换逻辑失效已排序的表会让某些快速排序实现退化全相同的元素会让比较逻辑陷入死循环。它们不是从需求里推出来的是从「这类代码通常怎么写」里推出来的。正因为来源是经验错误推测法只能当补充不能当主力。一个有经验的人能推测出七八个易错点一个新人可能一个都想不出来同一个功能换个人推测结果完全不同。把它和等价类、边界值搭配使用才合理前面几种方法保证覆盖面错误推测法负责补上那些「说不上为什么但就是感觉会出问题」的角落。5. 容易搞混的五组概念别把等价类和抽样混为一谈方法的名字都很好记用起来却经常走样。下面这五组混淆点是刚接触用例设计时最常出现的。5.1 误区一等价类划分等于随便挑一个代表易混点把「每个等价类挑一个代表」理解成「每个输入框随便填个值」。为什么混两个动作表面上都是「挑一个值」形式上几乎一样看不出区别。怎么区分看这个值是不是「有依据地挑的」。等价类的代表必须能说清楚它属于哪个类、这个类对应需求的哪句话。三角形判定里选 4、4、5 而不是 3、4、6是因为前者能覆盖「等腰」这个类后者只是又一个一般三角形。挑不出依据的代表就是抽样不是等价类划分。5.2 误区二边界值就是最大值和最小值易混点一说边界值就只测 1、12、31、2050 这几个端点。为什么混名字里带「边界」直觉上就是「两头」。怎么区分边界值是一组点不是一个点。以下界为例至少要取下界减一、下界、下界加一三个值上界同理。只测 1 和 12测不出「月份等于 0 时程序是报错还是崩溃」测了 0 和 13才知道判断条件写的是1m12还是0m13。三个点连起来才勾出这条边。5.3 误区三预期结果写「显示正常」也算写了易混点预期结果栏填了字就认为这一项完成了。为什么混填表的人心里其实知道「正常」是什么意思写下来时没意识到别人不知道。怎么区分拿这条用例给一个没参与过需求评审的人执行看他能不能给出确定的是或否。给不出就说明预期结果不合格。合格的写法一定包含可观察的具体对象哪句文案、哪个页面状态、哪条数据记录。5.4 误区四步骤写得越细用例质量越高易混点把「点击用户名输入框」和「在用户名输入框输入 test」拆成两步甚至把「移动鼠标到按钮上」也写进去。为什么混细致看起来是严谨的表现多写总比少写好。怎么区分看这一步是否影响判定结果。影响结果的操作必须写不影响结果的鼠标轨迹、窗口位置不必写。步骤过细的用例有个副作用一旦界面改版几十条用例要逐条改步骤维护成本高到没人愿意维护最后整批用例作废。判定的标准是「换个人按这个步骤走能不能得到同一个结果」而不是「步骤有几行」。5.5 误区五因果图和判定表是两种并列的方法易混点认为这两个名字代表两套独立的技术学一个就够。为什么混教材里它们经常被并排放在同一章名字也都很「专业」。怎么区分因果图是中间产物判定表是最终产物。因果图负责把散落的业务规则理清、把中间状态显式地画出来但图本身不能逐条执行判定表负责把逻辑摊成一张可执行的表。实际工作中简单逻辑可以直接写判定表跳过画图逻辑绕到画不清楚时才需要先画因果图理思路。它们是上下游关系不是二选一。6. 什么时候该用哪一招方法选择的边界方法不是越多越好用错了反而浪费时间。判断标准其实只有两条输入之间有没有耦合以及错误的代价高不高。输入彼此独立、逻辑简单比如一个只校验格式的输入框等价类加边界值就够了硬上一张判定表纯属自找麻烦。输入之间有明显的「与」「或」「非」组合比如权限判断、计费规则、状态机流转判定表几乎是必选项因为它能一次性把 2 的 N 次方种组合摊平漏掉哪一列一眼就能看出来。逻辑绕到连判定表都填不下去说明中间状态太多这时候先画因果图理清层次把中间结点编上号再转成表会比硬填快得多。至于错误推测法它永远只能当最后一道补充用来捞那些前几种方法覆盖不到的、说不清理由但就是不放心的角落。场景特征首选方法理由单个输入框规则简单等价类 边界值成本最低覆盖够用多个条件组合决定一个结果判定表组合能穷尽漏项可视逻辑多层嵌套、有中间状态因果图转判定表先把层次理清再摊平有历史缺陷高发区错误推测法补充经验只能补不能替代用户路径长、跨多个页面场景法单点验证无法反映整体反过来说什么时候别用也得说清楚。需求还没定下来、业务规则本身就含糊的时候别急着画判定表——你画出来的表只是自己的一种猜测跟需求方确认完可能整张推翻。同理代码实现还没出来、接口都在变的时候别把用例的步骤写到操作级别改一次全废。还有一种情况是团队根本没有缺陷管理工具、用例写完就锁在文档里没人执行这种时候写多精细的用例都是自我感动先把执行链路打通再说。我刚做测试那阵子最喜欢干的事就是给每个功能都配一张判定表觉得表格越复杂越显得专业。结果有一次给一个只有两个输入框的查询页面硬生生画了张八列的表需求方看了半天问我这不就是一个「时间不能早于今天」吗那之后我每次动手写用例前都强制先问自己两个问题输入之间有耦合吗如果这条用例翻车了损失有多大两个问题都答不上来的时候就先写三条最简单的场景用例跑一遍再决定要不要上重武器。希望这套判断顺序能帮你少走点弯路。本文还有配套的精品资源点击获取