精简测试用例:配对测试实战指南
Treeify 专注把测试设计变成可建模、可评审、可持续迭代的过程——用结构化方法把问题空间拆开,再生成更少但更有覆盖的用例。
想一起把测试设计做得更工程化,欢迎来共创/内测。
添加 V:【TreeifyAI】进内测共创群,获得 Treeify 内测资格 / 免费 credits / MCP Server 试用
当测试维度不断叠加(设备 × 浏览器 × 角色 × 支付方式 × 语言 …),组合数量会迅速膨胀到难以管理。
配对测试(Pairwise,t=2)通过“覆盖所有成对组合至少一次”的原则,让你用较少的测试数量,获得尽可能多的交互覆盖。必要时可以提升到三元组合(t=3)。
1. 本文解决什么问题
这份文档主要面向两类读者:
- 测试新手:面对大量组合,不知道如何系统地挑选测试用例。
- 有经验的测试工程师:希望用一套可复用的方法,控制组合规模,同时维持较高覆盖。
阅读后,你会理解并能够实践:
- 如何用配对/组合技术,从“所有可能组合”中提炼出一个精简但有质量的测试集。
- 如何设计因素、水平、约束、种子用例和权重。
- 如何把组合测试结果交付为“可审查、可追溯、可复用”的测试资产。
- 如何在真实场景中使用:UI 组合矩阵、API 参数组合等。
2. 核心概念
2.1 因素与水平
-
因素(Factor) :一个独立维度,例如:设备、浏览器、角色、支付方式。
-
水平(Level) :某个因素的具体取值,例如:
- 设备:iOS / Android / Desktop
- 浏览器:Safari / Chrome / Firefox
在设计组合前,需要先把每个因素的取值明确列出来,尽量避免模糊表达(如“移动端”这种模糊类目,最好拆成 iOS 与 Android)。
2.2 配对测试(Pairwise,t=2)
- 目标:生成一组测试用例,使所有“跨因素的成对水平组合”至少出现一次。
- 好处:在大幅减少组合数量的前提下,仍能覆盖大部分具有代表性的交互问题。
可以简单理解为:
我不测试所有组合,但保证任何两个因素的任意取值至少在某个用例里“见过一次面”。
2.3 三元组测试(t=3)
- 对所有“三个因素的组合(t=3)”做类似覆盖。
- 成本更高,适合对风险较高、交互复杂的区域(例如:设备 × 浏览器 × 支付方式)使用。
- 一般不会对所有因素都上 t=3,而是对关键子集(例如 3–4 个关键因素)使用。
2.4 约束(Constraints)
用来排除不可能或无意义的组合,例如:
Android × Safari在实际产品中不存在。- 某些支付方式在特定地区不可用。
约束越清晰,生成结果越贴近真实业务,也减少浪费测试资源在“不会发生的组合”上。
2.5 种子 / 必含用例(Seeds)
业务上必须包含的测试组合,例如:
- “会员 × 退款 × 中文语言”是曾经出过事故的组合。
- 新上线的某个支付渠道 + 某个地区,需要重点回归。
这些种子用例可以在生成器运行前先固定,确保不会被“简化过程”意外删掉。
2.6 权重(Weights)
对一些更高风险或更重要的组合增加权重,例如:
- 新增支付方式 × 特定地区。
- 特定浏览器 × 特定设备,是主要用户群。
权重常用在更高级的生成工具中,目的是让生成器优先覆盖高风险交互,即便整体组合数量被压缩。
3. 适用与不适用场景
3.1 适用场景
配对/组合测试适合“多维度组合,但单条用例本身比较独立”的场景,例如:
-
UI 组合矩阵
- 设备 × 浏览器 × 角色 × 语言
-
API 参数组合
- 排序字段 × 排序方向 × page_size × filter
-
功能开关 / 配置组合
- 多个 feature flag / AB 实验组合
-
兼容性测试
- 不同 OS / 浏览器 / 网络条件 / 本地化设置的组合
关键特征是:每个组合都代表同一业务流程下的一次“配置变化” ,而不是复杂时序。
3.2 不适合单独使用的场景
配对测试并不是万能的,以下问题不宜仅依赖配对:
- 强时序依赖:状态机、流程、审批链 → 更适合用状态模型或场景建模。
- 数值边界 / 格式问题:输入范围、格式、单位 → 使用边界值 / 等价类。
- 并发类问题:锁、冲突、事务 → 更需要专门的并发与一致性测试。
- 高度依赖上下文的业务流程:例如复杂工作流多个步骤间有强依赖。
这类场景可以把配对测试当作补充,而不是主力方法。
4. 配对测试 8 步操作流程
这一节是可直接落地的“操作说明书”,做一遍之后基本就能掌握套路。
第 1 步:列出因素与水平
从 PRD / 现有实现 / 业务访谈中提取维度,并明确每个维度的取值。
示例:
- 设备:iOS / Android / Desktop
- 浏览器:Safari / Chrome / Firefox
注意:要把“模糊的分类”拆开,例如“Mobile”拆解成 iOS/Android,而不是直接当作一个单独水平。
第 2 步:写出约束
排除技术上或业务上不可能的组合。
示例:
NOT (Device = Android AND Browser = Safari)
在复杂业务中,也可以写成一组规则化表达,方便维护和自动生成。
第 3 步:选择强度(t)
- 一般场景:t = 2(Pairwise) 已能带来明显收益。
- 对交互复杂、事故成本高的领域(支付、结算、风控):可以对关键因素子集使用 t = 3。
不要一上来就把所有因素都设成 t=3,否则组合量会变得很难控制。
第 4 步:添加种子用例
根据历史缺陷、业务经验、上线风险,挑选必须包含的组合,例如:
- “会员 × PayPal × 法语”
- “Desktop × Chrome × 高价值用户 × 特定地区”
这些种子用例会被直接纳入最终集合,生成器在此基础上再补齐缺失的组合。
第 5 步:生成最小用例集合
使用工具或脚本进行生成:
- 输入:因素、水平、约束、种子用例。
- 输出:满足配对约束的最小(或接近最小)用例集。
这里不一定要追求绝对最优解,可读性和可维护性同样重要。对很多团队来说,一个略大但易理解的集合,往往比一个压到极限的“数学最优解”更好用。
第 6 步:分开处理无效 / 非法输入
一个常见错误是:把非法输入(格式错误、越界值)也当作“水平”塞进去,这会让生成器产出大量实际不会被执行的组合。
建议:
- 组合生成器只负责有效组合。
- 非法输入由边界值/等价类用例单独覆盖。
- 需要时,可对某个组合同时设计“合法输入用例 + 非法输入用例”,但这属于测试设计过程,而不是生成器负责的部分。
第 7 步:在选定用例中叠加边界值
生成的组合通常只规定“维度”,没有规定“字段具体输入值”。
例如:
- “iOS × Safari × Member × PayPal × fr-FR” 这条用例,可以选择使用“最大长度优惠码”、“最小订单金额”等边界值来提高该用例的价值。
做法是:
- 在覆盖矩阵中标记哪些用例被“叠加了边界测试”。
- 让少量组合同时承担“交互覆盖 + 边界覆盖”的责任。
第 8 步:产出覆盖矩阵
组合生成完成后,建议做一张简易的覆盖矩阵,用来说明:
- 每个用例覆盖了哪些关键配对(或三元组)。
- 是否所有关键配对都得到覆盖。
这张矩阵可用于:
- 代码评审/测试评审时快速说明“我们测试到了什么”。
- 复盘时回看哪些组合仍未覆盖。
5. 实例 A:UI 结账矩阵
5.1 因素与水平
| 因素 | 水平 |
|---|---|
| 设备 | iOS, Android, Desktop |
| 浏览器 | Safari, Chrome, Firefox |
| 角色 | Guest, Member |
| 支付方式 | Card, PayPal |
| 本地化 | en-US, fr-FR |
这里如果后续要增加更多水平(例如更多语言、更多支付渠道),也可以在同一结构下扩展。
5.2 约束
NOT (Device = Android AND Browser = Safari)
意味着生成器不会生成 Android + Safari 这种组合,因为产品中本身就不支持。
5.3 示例生成结果(12 条用例)
下面是一组可行的 Pairwise 结果示例(并非唯一解)。实际生成时,只需满足“所有成对组合至少出现一次”:
| 用例 | 设备 | 浏览器 | 角色 | 支付 | 本地化 |
|---|---|---|---|---|---|
| C01 | iOS | Safari | Guest | Card | en-US |
| C02 | iOS | Chrome | Member | PayPal | fr-FR |
| C03 | iOS | Firefox | Guest | PayPal | fr-FR |
| C04 | Android | Chrome | Guest | Card | fr-FR |
| C05 | Android | Firefox | Member | Card | en-US |
| C06 | Desktop | Safari | Member | Card | fr-FR |
| C07 | Desktop | Chrome | Guest | PayPal | en-US |
| C08 | Desktop | Firefox | Member | PayPal | fr-FR |
| C09 | iOS | Safari | Member | PayPal | en-US |
| C10 | Android | Chrome | Member | PayPal | en-US |
| C11 | Desktop | Chrome | Member | Card | fr-FR |
| C12 | iOS | Firefox | Member | Card | en-US |
实际项目中,你可以根据生成工具输出调整顺序、补充备注,不必与以上示例一模一样。
5.4 使用建议
-
可以挑几条用例叠加“业务边界”,例如:
- 在 C09 中使用最大长度优惠码 + 最低订单金额。
- 在 C07 中使用特殊字符用户名。
-
为每条用例定义验证点(oracles):
- 页面渲染正常、关键功能可用。
- 支付流程正常完成(或被正确拒绝)。
- 日志中记录设备/浏览器/角色等维度信息。
5.5 风险加权建议
若某些因素组合的历史缺陷较多,例如“移动端支付 × 某浏览器”:
- 在生成器中提高这类组合的权重;
- 或者在生成结果中标记“高优先级测试”,安排在回归集前半部分执行。
6. 实例 B:API 查询参数组合
6.1 因素与水平
| 因素 | 水平 |
|---|---|
| sort_by | created_at, price |
| order | asc, desc |
| page_size | 10, 50 |
| filter | none, in_stock |
| include | none, relations |
这些因素构成了一个典型的列表查询接口参数空间。
6.2 约束
在本示例中:
include=relations时,要求page_size <= 50,而我们的取值本身已满足,不需要额外约束。- 若真实业务中有更严格限制,可显式写出约束规则。
6.3 示例生成结果(8 条)
| 用例 | sort_by | order | page_size | filter | include |
|---|---|---|---|---|---|
| A01 | created_at | asc | 10 | none | none |
| A02 | created_at | desc | 50 | in_stock | relations |
| A03 | price | asc | 50 | none | relations |
| A04 | price | desc | 10 | in_stock | none |
| A05 | created_at | asc | 50 | in_stock | none |
| A06 | price | desc | 50 | none | none |
| A07 | created_at | desc | 10 | none | relations |
| A08 | price | asc | 10 | in_stock | none |
同样,这只是一个示例解。你可以用任何工具生成自己的组合,只要保证覆盖要求即可。
6.4 建议检查点(Oracles)
对每个组合,建议至少验证:
-
排序
- 主要排序字段是否正确;
- 若存在相同
created_at,是否有稳定次级排序(例如id)。
-
响应契约
- 字段结构是否符合接口 schema;
- 当
include=relations时,关联实体是否以约定方式返回。
-
性能
page_size=50时,响应时间是否满足 p95 指标。
-
日志证据
- 请求参数是否完整记录在日志 / trace 中(便于线上排查)。
7. 何时使用 t=3(三元组合)
在大多数业务中,t=2 的配对测试已经能够发现相当比例的交互问题。但在以下场景,可以考虑对部分因素使用 t=3:
-
多层级功能开关组合:
- 如 FeatureA × FeatureB × FeatureC 决定某个核心功能是否可用。
-
多维兼容热点:
- 设备 × 浏览器 × 语言 三者同时对渲染产生影响。
-
风控/计费逻辑:
- 客户类型 × 产品类型 × 地区 的组合影响费率或限额。
建议做法:
- 不要对所有因素一刀切使用 t=3。
- 先从风险视角挑选 3–4 个关键因素,对它们进行三元组合覆盖。
- 其他因素保持 t=2 或单维度覆盖即可。
8. 评审要点(质量闸口)
在评审一个组合测试设计时,可以用下面的清单做简单闸口:
- 因素与水平已列全,且描述规范、无模糊概念。
- 约束明确,避免生成不可能存在的组合。
- 已根据风险合理选择 t=2 或 t=3(而不是默认全用 t=3)。
- 种子用例覆盖关键业务路径和历史缺陷路径。
- 生成集合规模合理(既不过大,也不明显不足)。
- 至少在部分用例中叠加了边界内容(长度/金额/日期等)。
- 对每条用例都定义了清晰的验证点(oracles)和日志证据。
- 有一份覆盖矩阵或说明,能看出成对(或三元)组合是否已全覆盖。
9. 常见误区
在实际项目中,配对测试常见的误用方式包括:
-
用 pairwise 替代边界测试
- 配对测试解决的是“组合覆盖”,不能取代边界值/等价类。
- 建议先完成输入边界设计,再用配对测试选组合。
-
没有约束
- 不写约束会让生成器产生大量业务上不成立的组合,浪费时间。
-
混入非法输入
- 非法输入应该由边界值/等价类专门覆盖,而不是当作组合的一个水平。
-
水平过度细化
- 把每个浏览器版本、每个语言地区都当一个水平,组合量会非常大。
- 建议按业务风险进行分组,例如“主流浏览器”、“次要浏览器”等。
-
试图用 pairwise 找出时序问题
- 配对测试对“静态组合”非常有用,但对涉及状态和时序的缺陷效果有限,应结合状态模型和流程测试一起使用。
10. 可复用模板:组合测试设计文档
# 组合测试设计 — <模块名>
## 1. 因素与水平
- 因素 A:a1 / a2 / …
- 因素 B:b1 / b2 / …
- 因素 C:c1 / c2 / …
- …
## 2. 约束
- NOT (A = a2 AND B = b1)
- NOT (Device = Android AND Browser = Safari)
- …
## 3. 强度选择
- 使用 t = 2(pairwise);如需覆盖三元交互则使用 t = 3,并限定在关键因素子集上。
## 4. 种子用例
| id | A | B | C | 备注 |
|-----|----|----|----|-------------------|
| S01 | … | … | … | 历史缺陷路径 |
| S02 | … | … | … | 核心业务路径 |
## 5. 生成结果
| id | A | B | C | D | … |
|-----|----|----|----|----|---|
| T01 | | | | | |
| T02 | | | | | |
| … | | | | | |
## 6. 边界值叠加说明
- 在 T03 使用最大长度字段 X = …
- 在 T07 使用最小金额 Y = …
- 在 T09 使用跨时区日期边界 …
## 7. 覆盖矩阵(示意)
- 说明每个关键成对/三元组合由哪些用例覆盖。
- 例如:Device × Payment,列出组合 → Txx 用例 ID。
## 8. 检查点(Oracles)
- 业务结果:是否接受/拒绝、价格计算是否正确。
- API 契约:响应结构、错误码。
- 日志/监控:是否记录 device、browser、locale、rule_id 等字段。
11. 新手行动路径
10 分钟:快速入门
- 选一个你最熟悉的业务功能(例如:结账页、登录页)。
- 列出 3 个因素,每个因素 2–3 个水平。
- 手工列出全部成对组合,并尝试压缩成 6–10 条用例,保证每个成对组合至少出现一次。
更多推荐
所有评论(0)