尧图精选

因果图法实战:从需求分析到决策表,搞定黑盒测试组合场景

🕒 发布时间:2026/10/2 20:21:26 📁 来源:尧图网络
每个做软件测试的人迟早都会遇到这么一类bug单独测试每个功能都正常一旦把多个输入条件组合起来就会出现莫名其妙的问题。我刚入行那会儿被一个“只有特定选项组合下才会触发”的缺陷折磨了两天排查到最后才发现是需求文档里写了一个非常隐蔽的条件分支。从那之后因果图法这个名字在我心里的分量就不一样了——它不是面试八股文里背一背的术语而是一套能真正把“组合爆炸”问题梳理清楚的黑盒测试设计方法。无论是做功能测试、接口测试还是写自动化用例前的场景设计因果图法都能帮你在动手执行之前把逻辑关系和测试范围理得明明白白。这篇文章我就把自己从理论到实战用因果图法的经验完整拆开来。包括它解决什么问题、符号和约束怎么用、从需求文档到因果图再到决策表的完整链路以及我在真实项目里踩过的一些坑和搭配其他测试方法的心得。如果你正在备考软件测试面试或者刚接手一个条件判断比较多的模块这篇文章应该能让你少走不少弯路。1. 为什么我劝你别小看因果图法它堵住的是组合场景这个最大漏网之鱼测试设计的方法其实不少等价类划分解决“用最少的数据覆盖尽可能多的类型”边界值分析解决“在边界附近最容易出错”的问题场景法解决“按用户实际操作路径来测”的问题。但有一类问题上述方法都不好直接解决——多个条件之间的组合关系。举个最简单的例子一个登录功能用户名和密码都要校验登录是否成功还取决于账号状态是否正常。这三个条件各自有“合法/非法”两种状态如果不懂组合设计你可能会凭感觉挑几组数据来测。但用户实际使用中是会把各种情况拼在一起的漏掉一组组合很可能就把一个bug漏到了线上。因果图法就是为这种场景设计的。它的核心思想很朴素把需求里所有的输入条件当作“因”把所有的输出结果当作“果”然后分析它们之间的逻辑关系把这个关系画成一张清晰的图。有了这张图之后再把它转换成一张规则表从规则表里导出最终要执行的测试用例。用大白话说它就是把“如果……那么……”这种散落在需求文档里的逻辑变成一步一步可推导、可验证的测试设计过程。我第一次被因果图法“救”回来是在测一个电商优惠券模块。那个需求里有满减、打折、包邮、会员专享等等一堆规则叠加在一起当时我头都大了。后来我按照因果图法的思路把每条规则都当成一个输入条件把用户最终看到的实付金额和是否包邮当作输出结果一步一步把关系图画出来再转成规则表整个理路瞬间就清晰了。那一轮测试我不仅把组合场景覆盖得很全还反过来发现了需求文档里两个规则互相矛盾的地方。从那个时候起我就特别笃定凡是有多个条件互相作用的功能因果图法就是那面最该挂上的安全网。2. 因果图法的建模语言从“因”与“果”到四种逻辑符号和五类约束想真正用起来因果图法不能光记住“原因”“结果”这两个概念还得掌握它的符号系统和约束规则。这部分看似简单却是很多人画图画到一半就乱套的根源。2.1 原因、结果与中间节点先把需求拆成最小的逻辑单元因果图法把系统的外部输入条件称为“原因”把系统的输出或状态变化称为“结果”。在实际分析时一个“原因”可以是一个输入项是否合法也可以是一个开关是否打开甚至可以是一个外部事件是否发生一个“结果”可以是界面上出现某条提示也可以是数据库里写入某条记录还可以是跳转到某个页面。关键是原因和结果都要是可以明确判断真假的命题。有些复杂的逻辑还会出现“中间节点”。中间节点既不是什么真正的输入也不是最终输出而是组合了多个原因之后形成的中间状态。打个比方你判断“是否允许登录”这个结果时会先判断“验证码正确且账号未被锁定”这个中间条件而这个中间条件又由两个更基础的原因构成。中间节点的作用是让大图不至于一下子变得太复杂画图的时候可以分层去表达。2.2 四种逻辑符号对应需求里最常见的几类关系因果图法里的逻辑关系符号并不多就四种恒等、非、或、与。不过它们组合起来能表达的逻辑很丰富。恒等关系就是“原因出现结果就出现”。比如条件“按下提交按钮”结果“表单被提交”这就是一条恒等关系。非关系表示“原因不出现时结果才出现”。最典型的是各种“当输入不合法时给出错误提示”这里的结果和那个“不合法”之间就是非的关系。或关系表示“多个原因中任意一个成立结果就成立”。比如“用户名或密码为空提示登录失败”两个原因之间是或的关系。与关系表示“多个原因同时成立结果才成立”。比如“手机号正确且验证码正确且账号未冻结允许登录”这里就是典型的多条件与关系。画图时这些符号一般用带标记的连线来表示常见的是在连接线上标字母或用逻辑门图形表达。但在实际工作中真不一定非要画出多么标准的图形重点是把你理解到的逻辑结构准确地可视化出来。有些团队在评审测试方案时用文字加上简单的逻辑表达式反而沟通起来更高效。2.3 五类约束用来表达现实世界里不成立的条件组合光有逻辑符号还不够因为真实业务里很多原因之间是互斥的、包含的、或者有依赖关系的。这些现实世界的限制单靠逻辑运算符表达不了需要用到约束。我按自己理解整理了一下这五类约束可以这样记E互斥Exclusive多个原因中至多只能有一个成立。比如下拉框里选了“个人用户”就不可能同时选“企业用户”。I同或Inclusive多个原因中至少有一个成立。比如支付方式“微信支付”“支付宝支付”“银行卡支付”里至少要选一种。O唯一One多个原因中有且仅有一个成立。比如单选项里“男”和“女”必须且只能选一个。R要求Require一个原因成立时要求另一个原因也成立。比如选择了“企业认证”就要求填写“企业名称”。M屏蔽Mask一个原因成立时另一个原因就不允许出现。比如“不再显示该弹窗”一旦开启那么“显示欢迎弹窗”的条件就被屏蔽掉。约束是整个因果图法里我最喜欢也最怕的一部分。喜欢它是因为它能替你做减法把大量不可能会发生的条件组合直接剪掉规则表的规模一下就降下来了怕它是因为如果分析需求的时候漏掉了约束画出来的图虽然形式上没问题但导出的测试用例会包含一堆现实中根本不存在的场景白白浪费执行时间。3. 从需求文档到因果图的完整推演一个自动售卖机案例的逐步拆解这一节我通过一个相对完整的案例带大家走一遍从需求文本到因果图的流程。这里我选一个自动售卖机的购买流程原因很简单它条件清楚、结果可控而且贴近日常没有任何行业门槛。3.1 需求段落先把原始需求内容原样摆出来假设需求文档里是这么写的“用户可以向自动售卖机投入硬币并选择商品。当投入的总金额达到或超过商品价格时可以购买该商品当投入金额不足时提示‘余额不足’并保持等待投币状态。商品售出后如果有多余的钱则进行找零如果没有多余的钱不找零。如果用户选择取消购买则退回所有已投入的金额。”先别急着画图测试用例设计的第一步永远是“吃透需求”。把这段文字读三遍之后我会带着两包不同颜色的荧光笔去标注一包标“原因”相关的词一包标“结果”相关的词。3.2 识别原因、结果与中间状态标注是画好图的前提我一般会从这句话里的动词和判断词入手。原因通常是“用户做了什么”“系统接收到什么条件”结果通常是“系统给出什么反馈”“系统进入什么状态”。从这个需求里我可以识别出这样几个原因原因C1用户投入了硬币。原因C2用户选择了商品。原因C3投入总金额大于等于商品价格。原因C4投入总金额小于商品价格。原因C5用户点击取消购买。也许有朋友会疑惑C3和C4不是刚好相反吗为什么都当成原因列出来这里要把“原因”理解成“系统在每个判断节点上要检查的条件”而不是最终用户输入的那个动作。用户输入的只有投币、选商品、取消但系统在判断时要分别检查“钱够不够”和“钱不够”这两个分支所以它们都可以是图中的原因节点前提是它们之间要加上互斥约束。再看结果结果E1提示“余额不足”保持等待投币状态。结果E2售出商品。结果E3找零。结果E4不找零。结果E5退回所有已投入金额。除此之外还有一个中间状态值得拎出来投入金额是否达到商品价格。这个中间状态可以由C3或C4来体现可以直接用也可以设成一个单独的中间节点“金额充分性”让图更清晰。我倾向于保留C3、C4作为原因不再额外加中间节点因为这里的关系已经足够直白。3.3 画出逻辑关系并补充约束让这张图反映真实世界现在开始连线。先说最简单的部分当C1、C2、C3三个原因同时成立时系统会售出商品这就形成了一条与关系指向E2。在E2成立的基础上如果投入金额大于价格就找零等于价格就不找零。但需求原文里没有单独把“投入金额大于价格”和“投入金额等于价格”分开列出来这其实是个容易埋坑的地方。正确做法是拆成两个条件原因C6“投入总金额大于商品价格”和原因C7“投入总金额等于商品价格”。再加上原来的C3“投入总金额大于等于商品价格”你会发现它们之间是有包含关系的。这时约束就该上场了C3和C4之间是互斥的C6和C7之间也是互斥的。C3成立时C6和C7二者必居其一。继续说因果链路C6成立且E2成立则结果E3找零C7成立且E2成立则结果E4不找零。而C1、C2、C4同时成立时说明用户选了商品但钱不够则结果E1提示余额不足。C5一旦成立无论当前处于什么状态都会触发结果E5退回全部金额。这里C5和C2之间其实存在实际业务上的约束用户只有在选完商品之后才可能看到取消按钮但需求里没有说明所以我标一个“M屏蔽”约束表示C5成立时C2的后续购买流程不允许继续输出售货结果。这张图画完之后再回头看一遍需求原文我立刻发现了一个潜在矛盾当用户选择取消购买时如果此时投入金额已经等于商品价格“是否应该先退币再取消”在原文里并没有说清楚。这就是画因果图的价值——它逼着你去澄清需求而不是等到测试执行了半天才发现理解有歧义。3.4 常见卡壳点图越画越乱的三个原因很多初学者画到一半就开始烦躁通常是因为下面三个问题。第一把“原因”理解得太窄。有人只把用户操作当原因忘了系统内部的判断条件也是原因。其实只要是逻辑判断的分支入口都可以作为原因节点。第二边界条件没有拆细。比如“金额大于等于价格”这种条件如果不在因果图阶段拆成“大于”和“等于”后面推导测试用例时就很可能漏掉“刚好等于价格”这个最容易出错的数据点。第三约束漏标。漏标约束的直接后果就是决策表里多出一堆无意义的规则让用例数量虚胖。4. 用决策表搭桥把因果图转化成可执行测试用例的关键工程因果图画得再漂亮也不能直接拿去执行测试。它的下一步通常要从一个二维表里走一遍这就是决策表也叫判定表。整个过程我觉得特别像把“电路图”转成“真值表”——逻辑图表达的是关系表格表达的是可枚举的规则。4.1 决策表的基本结构条件桩、动作桩和规则列决策表一般分成四个区域条件桩区、动作桩区、条件项区、动作项区。条件桩是列出所有原因动作桩是列出所有结果条件项是每个原因在当前规则列下的取值成立或不成立动作项是每种条件组合下对应的结果是否触发。把因果图转成决策表的步骤是这样的列出全部原因放到条件桩列出全部结果放到动作桩然后枚举所有符合约束的条件组合逐列填充条件项再根据因果图的逻辑关系推导出每个结果是否成立填入动作项。每一列就代表一条决策规则指向一组可执行的测试用例。这么做的好处是怎么强调都不过分它让“为什么设计这些用例”这件事变得可追溯。评审时别人问你“这几个用例是怎么来的”你直接甩出决策表逻辑链路一眼就能看清比嘴上解释半天管用太多。4.2 从理论上限到实际规则组合爆炸怎么被约束压下来不夸张地说因果图如果不加约束直接转决策表规则的规模会非常吓人。假设有5个原因每个原因有“成立”和“不成立”两种取值那么完整的组合就是2的5次方等于32条规则如果有10个原因就是1024条20个原因就是一百多万条。如果真到那一步因果图法的优势就彻底变成了灾难。所以约束的作用必须被充分利用。还是拿售卖机案例来说C3和C4互斥C6和C7互斥这就直接把一大半永远不会出现的组合从决策表里删掉了。再加上C5对后续流程的屏蔽关系最终的规则数会大幅缩水。实践中我通常遵循一条原则先加约束剪枝再检查剪掉之后是否仍有某个关键分支没有被覆盖到。千万不要为了省用例数量把不该剪的给剪了。4.3 从规则列到测试用例每一条规则都不是只能生成一条用例很多教程讲到决策表就停了好像把规则列出来就等于用例设计完了。但实际落地的时候还需要再往前走一步。一条规则往往只描述了“某个条件成立/不成立”这样的事实可测试执行是需要具体数据的。举例来说规则里写着“投入金额小于价格——余额不足”真正执行测试时你要造一个具体的小于价格的数据比如商品价格3元我投了2元9角还要检查此时是停留在等待投币状态还是系统直接退币。另外数据本身还可能有边界比如“小于”包含1分钱差额也包含几乎等于价格的差额这两种情况在实现时往往走的不是同一条代码路径。所以我的习惯是从一条规则出发再结合边界值分析法补充具体的数据取值让同一个规则最终生成一或多条真正可执行的测试用例。顺带说一下决策表本身还有一个好处是能检查完整性。把规则列完之后我会对着原需求逐条核对一遍看看有没有哪个“结果”在表格里完全找不到出发路径。如果有那多半是因果图阶段漏分析了。5. 没有中间节点就不好用复杂登录业务的因果图实战演示前面那个售卖机案例虽然完整但很多朋友看完可能还是觉得“这不就是个简单逻辑嘛凭脑子想也能想到”。没问题这一节上一个复杂度明显更高的例子一个带多条件风控的登录认证流程。这是我在实际项目里处理过的业务形态不是教科书里的玩具案例。5.1 一段真实风格的登录需求多个条件互相纠缠假设产品经理给出的需求是这样的“用户登录时需要输入手机号和密码。手机号必须为11位且以1开头密码长度必须在8到20位之间且必须同时包含字母和数字。如果手机号非法提示‘手机号格式错误’不再校验密码如果手机号合法但密码非法提示‘密码格式错误’如果手机号和密码都合法但账号在风控系统中被标记为风险账号提示‘账号异常请联系客服’如果账号正常则登录成功并跳转到首页。连续输错密码5次后账号锁定提示‘账号已锁定’。”读完这需求你第一反应是什么我当时的反应是如果用等价类划分硬做我可能会把手机号、密码、风控状态、锁定状态都分别测一遍但是“手机号合法密码合法风控正常但由于连续输错被锁定”这种组合很可能就漏掉了。5.2 因果图和约束设定分清层次让图别失控面对这种多条件的场景我习惯先列出条件及约束原因C1手机号格式合法11位以1开头。原因C2密码格式合法长度8-20含字母和数字。原因C3账号处于风控风险名单。原因C4账号已锁定由连续输错5次触发。原因C5用户不是首次登录涉及到某些产品还会区分新老用户这里先不加避免把案例撑太胖。结果结果E1提示“手机号格式错误”。结果E2提示“密码格式错误”。结果E3提示“账号异常请联系客服”。结果E4提示“账号已锁定”。结果E5登录成功并跳转首页。中间节点这里就有必要出现了。原因C1和C2没问题时才会进入下一步的账号状态判断所以可以设一个中间节点M1表示“基础校验通过”。M1 C1 与 C2。C3和C4都是账号状态层面的条件它们和M1的关系是“M1成立时才进一步判断C3和C4”。C3一成立直接走E3C4一成立直接走E4C3、C4都不成立走E5。约束方面C3和C4理论上是可以同时成立的——一个账号可能既在风控名单里又被锁定了。需求里没有说这种情况下优先级是什么这又是一个测试人员必须主动提的问题。在实际项目里我通常会拉上产品经理确认优先级而在测试设计时可以把C3和C4同时成立作为一条单独的危险组合规则放进决策表然后把产品经理最终确认的优先级作为预期结果。5.3 画出决策表草稿并手工化简一点点推效率反而最高画这个例子的决策表时我先按未经约束的全组合来枚举。C1、C2、C3、C4四个原因理论上有16条规则。但结合需求来看C1不成立的时候C2根本不会被校验E1是唯一结果C3和C4的取值对结果没有任何影响。这就像高中学物理时先做受力分析再列方程不变量可以直接合并。所以我把这16条规则压缩成了这样几条代表性规则规则1C1不成立无论C2、C3、C4是什么结果都是E1。这里可以拆成两个小用例手机号位数错误、手机号不以1开头。规则2C1成立、C2不成立无论C3、C4是什么结果都是E2。密码长度错误、缺少字母、缺少数字各算一个变体。规则3C1成立、C2成立、C3成立此时无论C4如何根据已确认的优先级结果都是E3。规则4C1成立、C2成立、C3不成立、C4成立结果是E4。规则5C1成立、C2成立、C3不成立、C4不成立结果是E5。经过这样一步手工化简原本让人头疼的十几条规则被压缩成5大方向而每个方向里再用等价类、边界值等手法补充数据细节。这种“因果图缩小范围、等价类丰富数据、边界值补充临界点”的组合打法是我实战中非常喜欢用的一套组合拳。5.4 把测试用例落到表格里可以直接照着执行的用例清单有了规则方向我通常会把用例表格整理成下面这样。这里不追求一张表覆盖一百条用例而是展示每类规则的核心关注点。用例编号覆盖规则手机号密码账号状态预期结果CG_01规则1-号码位数错误138001380010位任意合法值任意提示“手机号格式错误”CG_02规则1-首字符错误23800138000任意合法值任意提示“手机号格式错误”CG_03规则2-密码长度不足13800138000Abc1236位任意提示“密码格式错误”CG_04规则2-密码缺少字母13800138000123456789任意提示“密码格式错误”CG_05规则2-密码缺少数字13800138000Abcdefghij任意提示“密码格式错误”CG_06规则3-风控风险账号13800138000Pssw0rd123风控标记提示“账号异常”CG_07规则4-账号锁定13800138000Pssw0rd123连续输错5次提示“账号已锁定”CG_08规则5-全部正常13800138000Pssw0rd123正常登录成功并跳转首页看到这张表你应该能体会到因果图法在设计阶段的价值了。它把每个用例的来源链路都固定住了以后需求变更比如把密码规则改成“必须包含特殊字符”我只需要回到因果图上去改C2这个节点的判定然后重新推一遍决策表就能快速知道哪些用例需要调整哪些不受影响。6. 我在实际项目中积累的经验总结关于因果图法更冷门但实用的那些事最后这部分不教基础概念了就聊聊这些年真正用下来的体会。有些经验书上确实不太会写但对把你从“会画图”推向“会用图”特别有帮助。第一因果图法和判定表法不是两个割裂的方法而是一个流程的两个阶段。面试时经常被问“因果图法和判定表法有什么区别”很多标准答案会把它们做成并列关系。但我的理解是因果图负责把需求逻辑可视化判定表负责把逻辑结构规则化两者组合起来才是完整的测试设计过程。单纯画因果图却不转判定表只能算完成了需求分析单纯用判定表而不画因果图碰到复杂逻辑时你又很容易在条件桩排列上迷失方向。第二因果图法最适合的场景是“条件之间逻辑关系复杂且部分条件存在约束”的需求。如果测试对象只有两三个完全独立的输入框每个输入框只需单独校验那用等价类加边界值就够了硬上因果图反而显得笨重。可一旦出现像“A且B或C且非D”这种组合关系因果图法就是最合适的选择。第三面对执行时间紧张的迭代不要追求把因果图画得完美再动手。我见过不少测试同事对着需求文档憋半天就为画一张“标准”的因果图。其实因果图的核心价值在于逼你想清楚原因、结果和约束至于画得好不好看一点都不重要。我自己的做法是先用草稿纸拆出原因和结果清单再用逻辑表达式把它们的关系写下来最后才整理成一张正式的图去参加评审。第四因果图法对需求文档的反向推动力非常强。每次画图过程中发现的歧义和矛盾点我都会单独记录到一个“需求疑问清单”里在测试用例评审前发给产品和开发。这一点在团队协作里特别加分。因为测试人员最怕的不是用例设计慢而是测到一半发现开发的理解和需求文档完全不是一回事。第五关于自动化和代码生成现在的确有一些工具能辅助生成决策表和测试用例但我不建议刚开始学的时候过度依赖工具。手工完整走一遍从需求到因果图、从因果图到决策表、从决策表到测试用例的流程能在你脑子里建立起一套非常扎实的逻辑分析框架。以后哪怕工具换了流程变了你的分析能力也不会被替换掉。最后给准备面试的朋友一个建议面试官问因果图法时不要只背定义和符号。最好准备一两个自己实际分析过的案例讲清楚你是怎么从需求里识别原因和结果怎么处理中间节点怎么通过约束简化决策表以及怎么把决策表最终落地成测试用例的。这种“会做题也会讲题”的状态比背一百道八股文都更有说服力。因果图法说到底是逼我们用结构化的方式去面对复杂逻辑。软件测试这个行当越往后做越会发现发现bug的速度和技术工具关系不大真正拉开差距的恰恰是你能在测试设计阶段多想透多少层。而因果图法就是让我在“多想透”这件事上少走弯路的那张地图。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →