判定表
判定表把条件组合与对应动作放在同一张表中,用来检查“满足这些条件时,系统到底应该做什么”。它适合优惠、权限、运费等多条件共同决定结果的规则,也能暴露需求中没有说明的组合。
例如,“会员免运费”和“无法配送时拒绝订单”同时成立时,应该先拒绝还是直接创建免运费订单?写成判定表后,这个优先关系就必须得到明确答案。
1. 面试核心
先记住这几条,再读正文- 判定表中的每一列是一条条件组合与动作规则。先列条件,再列动作,不用当前代码的分支顺序替代需求规则。卡 · 条件与动作
- 完整布尔组合数量随条件数增长,可行组合的动作应明确且不冲突。缺少结果也是需要澄清的问题。卡 · 规则缺漏与精简
- 条件可以标为无关的前提是该条件所有可行取值都不改变当前规则的结果。无关不是未知,也不是不想测。卡 · 规则缺漏与精简
- 不可行组合需要约束证据,不能把当前界面无法操作误当成服务端永远收不到。输入非法时的拒绝行为仍可能需要单独测试。卡 · 不可行组合
2. 条件与动作
先看一组已经确认的示例规则:目的地不可配送时拒绝订单;可配送时,会员或者商品金额满 100 元免运费;其余订单收取 10 元运费。金额本身已通过合法性校验,会员身份由服务端确认。
这里有三个布尔条件:可配送 D、会员 M、满 100 元 A。三者均可独立取真或假,所以完整组合有 2³ = 8 个。
| 条件/动作 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 |
|---|---|---|---|---|---|---|---|---|
| 可配送 D | 否 | 否 | 否 | 否 | 是 | 是 | 是 | 是 |
| 会员 M | 否 | 否 | 是 | 是 | 否 | 否 | 是 | 是 |
| 满 100 元 A | 否 | 是 | 否 | 是 | 否 | 是 | 否 | 是 |
| 拒绝订单 | 是 | 是 | 是 | 是 | 否 | 否 | 否 | 否 |
| 运费 | 不计算 | 不计算 | 不计算 | 不计算 | 10 元 | 0 元 | 0 元 | 0 元 |
R3 说明不可配送的会员仍应被拒绝。若代码先判断会员直接返回免运费,且调用方误把报价成功当成可以创建订单,这列就能暴露规则优先级错误。
“不计算”也是有含义的动作约定:不能偷偷创建订单后再报错。涉及持久化时,测试需要确认拒绝后没有生成订单或扣减资源。
3. 规则缺漏与精简
判定表首先用来检查规则是否完整,然后才考虑减少重复。若某列无法填写,应该记录待确认问题;若两条需求要求同一组合执行相反动作,就要明确优先级或修改规则。
在本例中,D=否 时,会员和金额都不改变拒绝结果。可将 R1—R4 合成一列,并把无关条件写成 —:
| 条件/动作 | S1 | S2 | S3 | S4 |
|---|---|---|---|---|
| 可配送 D | 否 | 是 | 是 | 是 |
| 会员 M | — | 是 | 否 | 否 |
| 满 100 元 A | — | — | 是 | 否 |
| 结果 | 拒绝 | 运费 0 元 | 运费 0 元 | 运费 10 元 |
S1 包含四个原始组合,S2 包含两个,S3、S4 各包含一个,合计仍为八个,而且互不重叠。这里的精简保持了原规则的含义。
精简后的每列选一个代表,能够覆盖四类规则,但没有实际执行八个原始组合。若担心程序错误地让会员绕过配送检查,仍应保留 R3 或 R4;“表可以合并”和“这些输入永远没有必要测试”是两个不同判断。
4. 从表到测试
每条可行规则都要能转成输入和断言。对“满 100 元”这一条件,还要先用 边界值分析确定 99.99、100.00 等具体金额及精度约束。判定表处理条件组合,不能替代每个条件自身是否算对的检查。
下面的可运行小例子核对八个布尔组合,金额转换、会员查询和实际下单不在函数范围内:
from itertools import product
def shipping_result(deliverable, member, enough):
if not deliverable:
return "REJECT"
return 0 if member or enough else 10
# 顺序对应 D、M、A 各自按 False、True 枚举。
expected = ["REJECT", "REJECT", "REJECT", "REJECT", 10, 0, 0, 0]
for conditions, result in zip(product([False, True], repeat=3), expected):
assert shipping_result(*conditions) == result, conditions
print("8 rules checked")
输出为 8 rules checked。期望数组来自已确认的表,未调用被测函数生成;如果把实现的拒绝条件移到会员判断之后,再补相应错误分支,测试应能指出不符合表格的组合。
这段代码只证明示例函数符合表。真实系统还需核对条件来源:会员资格是否可信、金额是优惠前还是优惠后、配送范围的配置是否正确。若输入条件已经算错,后面的布尔函数完全正确也无法保证最终订单正确。
5. 不可行组合
不可行组合是被定义域或已证实约束排除的组合。例如单一支付状态不可能既等于“未支付”又等于“已支付”。把同一个状态拆成两个独立布尔条件,会产生本来不应存在的组合;可以改用一个枚举条件表达。
“前端不会发送”则通常不是充分证据。调用者可能绕过界面、使用旧客户端或构造请求。对于边界输入,应分别考虑:业务模型不承认该组合,服务端是否仍需检测并拒绝它。
删除不可行列时保留约束理由。否则后续规则变化可能让某列变得可行,而测试计划仍然把它排除。
6 · 面试题卡片
本页题目与参考回答
6.1 多个条件共同决定优惠或权限时,怎样建立判定表?
考察重点:条件、组合、动作和优先级的对应关系。
参考回答
先列出影响结果的独立条件及取值,再为每个可行组合写出明确动作。 同时确认规则优先级、拒绝行为和副作用。
每列再转成真实输入与断言。条件自身涉及金额、时间等阈值时,另补边界用例;不能只验证条件组合而忽略条件的计算是否正确。
6.2 判定表中的一列没有明确结果,应怎样处理?
考察重点:需求缺漏与实现事实的区别。
相关内容:规则缺漏与精简。
参考回答
将其作为需要确认的规则缺口,不能直接把当前代码输出认定为正确答案。 检查已有约定是否给出默认行为,并与规则负责人确认。
两个规则对同一组合要求不同结果时,同样要澄清优先级。确认后再更新表格和对应断言,使后续修改有稳定依据。
6.3 判定表里的“—”代表什么,什么时候可以合并列?
考察重点:无关条件、等价规则与实际输入覆盖。
相关内容:规则缺漏与精简。
参考回答
“—”表示该条件在当前规则的所有可行取值下都不改变动作。 只有其他条件和动作兼容,且合并后仍覆盖原组合、不引入错误组合时,才能合并。
未知结果不能写成无关。精简后的一个代表也不等于执行过被合并的全部输入;高风险组合仍可保留独立检查。
6.4 前端无法产生的条件组合,可以直接从测试里删除吗?
考察重点:定义域、边界校验与不可行约束。
相关内容:不可行组合。
参考回答
不能仅凭前端限制删除,接口还可能收到旧客户端或直接构造的请求。 真正不可行需要定义域或系统约束的证据。
业务模型中的非法组合,也可能需要服务端拒绝测试。应记录删除理由,并在约束变化时重新评估。
7. 参考资料
- ISTQB 及 CTFL 编写组:Foundation Level Syllabus 4.0.1,4.2.3 Decision Table Testing
- Python 3.12:itertools.product
来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明