一句话:软件测试是用有限的手段换取关于质量的信息的活动——它生产证据,不生产证明。
定位:软件测试/通用知识/ 的第一页,为其余五页提供术语与前提。读完后应能回答三个问题:测试到底在做什么、为什么测不完、"测试通过"为什么不等于"没有缺陷"。
上游:软件测试总目录 · 下游:测试过程模型与左移右移(测试放在流程哪里)、测试层级与测试类型(测什么属性)、软件质量模型ISO25010(质量的坐标系)
一、测试的定义:三种口径
| 口径 | 出处 | 定义要点 | 偏移 |
|---|---|---|---|
| 目的论 | Myers《The Art of Software Testing》(1979) | 测试 = 为了发现错误而执行程序的过程 | 强调"破坏性"意图,反"证明能用"心态 |
| 过程论 | IEEE 610.12-1990 | 在指定条件下运行系统或构件、观察或记录结果、对某个方面做出评价的过程 | 中性描述,含非执行活动(评审、静态分析) |
| 风险论 | ISTQB CTFL(现行大纲) | 一组用于评估产品质量、降低运行中失效风险的活动 | 把测试接到风险管理,含静态与动态 |
三种口径不冲突,而是历史叠加:Myers 定义"测试的意图",IEEE 定义"测试的动作范围",ISTQB 定义"测试在组织里的价值"。
本库采用口径:默认用 ISTQB 风险论口径(能包容评审、静态分析、右移观测等非执行活动);涉及"测试的意图"时引用 Myers。
1.1 三个必须分清的邻近概念
| 概念 | 关注对象 | 与测试的关系 |
|---|---|---|
| 测试(testing) | 产品 / 工作产品 | 通过执行与评审获得质量信息 |
| 调试(debugging) | 缺陷本身 | 测试发现失效,调试定位并修复;二者常被混为一谈 |
| QA / QC | 过程 / 产品 | QA 面向过程(建流程、防缺陷);QC 面向产品(查产物、找缺陷);测试是 QC 的主体手段之一 |
常见误答:"我是测试,所以我在做 QA。" 严格说测试属 QC;把测试数据用于改进流程,才产生 QA 价值。面试中能说清这一层区分,是"资深"信号。
二、测试的目的
| # | 目的 | 主要产出 |
|---|---|---|
| 1 | 评估工作产品(需求/设计/代码/文档) | 缺陷与风险清单 |
| 2 | 引发失效并观察 | 复现步骤与证据 |
| 3 | 提供决策信息(能否发布) | 质量报告 + 出口判据结论 |
| 4 | 降低运行中失效的风险 | 风险覆盖矩阵 |
| 5 | 验证需求与设计是否被满足 | 需求追溯矩阵(RTM) |
| 6 | 建立有依据的信心 | 基线数据与趋势 |
| 7 | 满足合同、法规与行业标准 | 合规证据 |
三类"反目的"(出现即说明测试定位跑偏):
- ❌ "证明程序没有缺陷" → 与 §五 穷尽测试不可能直接矛盾
- ❌ "帮开发背质量责任" → 测试与开发是同一质量目标的两种角色,不是责任转移
- ❌ "为了走流程 / 拿到签字" → 失去信息生产价值,退化为文档动作
三、七项测试原则(ISTQB)
| # | 原则 | 含义 | 实践推论 | 常见误用 |
|---|---|---|---|---|
| 1 | 测试显示缺陷的存在,不能证明缺陷不存在 | 测试的根本局限(Dijkstra, 1972) | 报告写"未发现缺陷",不写"没有缺陷" | 用"测试全过"作为发布唯一依据 |
| 2 | 穷尽测试不可能 | 输入、组合、时序、环境空间都是无限的 | 必须用风险与技术做抽样决策 | 声称"全覆盖",或放弃系统性 |
| 3 | 尽早测试(early testing) | 缺陷越早发现,修复成本越低 | 需求评审、可测性设计、静态检查 | 只前移"执行",没有前移"分析" |
| 4 | 缺陷聚集(defect clustering) | 缺陷分布不均匀,少量模块集中多数缺陷(帕累托) | 用缺陷历史定位高风险模块 → 加权投入 | 平均分配测试资源 |
| 5 | 杀虫剂悖论(pesticide paradox) | 同一批用例反复执行,不再发现新缺陷 | 定期评审并更新用例与数据 | 用例集多年不更新 |
| 6 | 测试依赖上下文(context dependent) | 电商与航天系统的策略不同 | 先定风险模型再定策略 | 照搬别家"最佳实践" |
| 7 | 无错谬误(absence-of-errors fallacy) | 修完所有已知缺陷,系统仍可能不可用 | 必须回到"需求是否对"(→ §四 确认) | 把缺陷清零当作验收通过 |
常被追问"哪些原则对管理最重要":#2 触发策略设计、#4 触发资源分配、#7 触发需求验证——三条直接决定测试计划的形态。
四、V&V:验证与确认
| 维度 | 验证 Verification | 确认 Validation |
|---|---|---|
| 经典提问 | Are we building the product right? | Are we building the right product? |
| 对照对象 | 规格说明 / 设计文档(内部约定) | 用户需求 / 使用场景(真实需要) |
| 主要手段 | 评审、静态分析、单元与集成测试 | 系统测试、验收测试(UAT)、现场试用 |
| 主要层级 | 单元 / 集成 | 系统 / 验收 |
| 典型失效 | "代码按设计实现了,但设计本身写错" | "功能全对,但用户不用 / 不好用" |
两者的交叉分类(不执行的也算测试):
| 静态(不执行) | 动态(执行) | |
|---|---|---|
| 验证 | 需求评审、设计走查、代码检查、静态分析 | 单元测试、集成测试、契约测试 |
| 确认 | 需求可测性评审、原型与可用性走查、验收判据评审 | 系统测试、验收测试、探索式测试、试点发布 |
关键提醒:静态测试是最容易被"测开/自动化"思维忽略的一半。同一个人既写代码又写单测时,静态评审往往是唯一能打破"作者认知盲区"的手段。 本库落点:SSD测试方法与体系 的 V&V 一节(Design Review / 走查 / 代码审计 / FMEA)就是这一栏的行业实例。
五、为什么测不完:穷尽测试的不可能性
5.1 四条独立论证
| 论证 | 内容 | 结论 |
|---|---|---|
| 输入空间 | 输入组合呈乘法/指数增长 | 无法枚举 |
| 时间与成本 | 每个用例都需执行 + 判定 + 记录 | 无法跑完 |
| 状态与时序 | 并发、中断、重试、分区、时钟漂移的组合远超代码路径 | 无法穷举 |
| 环境 | OS/版本/硬件/配置/数据状态的组合 | 无法穷举 |
一组数量级示例(面试口算用,非真实业务模型):
函数 f(int a, int b),32 位有符号整数
输入组合 = 2^32 × 2^32 = 2^64 ≈ 1.84 × 10^19 组
按 10^9 组/秒(相当乐观)→ 1.84 × 10^10 秒 ≈ 585 年
再加一个参数(3 个 int)→ 2^96 ≈ 7.9 × 10^28 组 → 天文数字
结论:一个"两参数纯函数"的输入空间就已无法穷尽,而真实系统的输入还包含状态、时序与环境。
5.2 Dijkstra 的原始表述
"Program testing can be used to show the presence of bugs, but never to show their absence!" —— Edsger W. Dijkstra, The Humble Programmer(EWD340, 1972)
两种常见误读:
- 误读 A:"所以测试没用" → 错。测试不能证明无缺陷,但能高效发现缺陷
- 误读 B:"那就全力上形式化验证" → 错。形式化验证的规格本身也可能写错(回到确认问题),且难以规模化到全系统
5.3 推论:测试的本质是"抽样 + 风险判断"
既然测不完,决定测试质量的就是两件事:
- 选对了要测的地方(风险驱动 → 测试设计)
- 测的方法足够有效(技术强度 → 测试技术)
这也解释了为什么"用例数量"不是好指标:一万个低价值用例的价值低于一百个高风险用例。
5.4 与测试互补的手段(是互补,不是替代)
| 手段 | 补的是什么 | 局限 |
|---|---|---|
| 形式化验证 / 模型检验 | 对特定性质给出证明 | 规格错误发现不了;状态空间爆炸 |
| 静态分析 / 类型系统 | 执行前拦截一类缺陷(空指针、越界、资源泄漏) | 覆盖的缺陷类别有限,有误报 |
| 代码评审 / 走查 | 发现"作者盲区"类问题(→ §六) | 依赖评审者水平,难以度量 |
| 运行时监控 / 可观测性 | 在生产持续观测真实行为 | 发现时用户已受影响 |
| 流量回放 / 差分测试 | 用真实分布替代人工抽样 | 需要流量与隐私合规 |
六、测试心理学:为什么单列一节
测试有效性高度依赖人的认知状态,而这是最难被自动化替代的部分。
| 现象 | 机制 | 后果 | 对策 |
|---|---|---|---|
| 作者盲区 | 作者按自己的设计假设检视,看不见假设本身 | 自测通过 ≠ 无缺陷 | 独立测试 / 交叉评审 |
| 确认偏误 | 倾向寻找支持"我的实现是对的"的证据 | 只测正常路径 | 强制"反例优先"清单 |
| 乐观偏差 | 低估复杂场景的失败概率 | 异常路径覆盖不足 | 用检查表驱动,而非凭感觉 |
| 独立性悖论 | 独立测试团队更有效,但沟通成本高、反馈慢 | 独立性与效率的取舍 | 按风险分层:高风险独立测,低风险自测 + 抽检 |
| 责任外部化 | "有测试兜底" → 开发质量意识下降 | 缺陷总量上升 | 质量目标共担(DoD 含质量门槛) |
一句话:测试是建设性的破坏——以"找出问题"为职业善意。团队文化若不接纳"被证伪",测试的有效性会被组织行为直接抵消。
6.1 测试独立性的五个级别(ISTQB)
"独立测试"不是非有即无,而是一条递进阶梯:
| 级别 | 测试设计者 | 独立性 | 典型代价 |
|---|---|---|---|
| 0 | 代码作者本人 | 最低(作者盲区) | 无额外沟通成本 |
| 1 | 同团队的另一开发者(交叉测试) | 低 | 需占用同伴工时 |
| 2 | 组织内的专职测试人员/测试组 | 中 | 反馈链开始变长 |
| 3 | 独立于开发线的测试团队(单独汇报) | 高 | 易形成"测试 vs 开发"壁垒 |
| 4 | 外部专家 / 第三方认证机构 | 最高 | 贵、周期长、不懂业务上下文 |
取舍原则:独立性越高,发现缺陷越有效,但反馈越慢、成本越高。没有"最优级别",只有与风险匹配的级别——安全关键产品常要求 L3
L4 的独立评价,业务系统则普遍采用 L1L2 + 高风险环节加独立测试。
七、术语对照表(本库统一口径)
| 英文 | 本库译法 | 说明与易混淆点 |
|---|---|---|
| error / mistake | 错误 | 人为的失误(人的行为) |
| fault / defect / bug | 缺陷 | 制品中的瑕疵(代码/设计/文档里的错误状态) |
| failure | 失效 | 运行时行为偏离预期(可观测现象) |
| verification | 验证 | 对照规格"做得对不对" |
| validation | 确认 | 对照需求"做的是不是对的" |
| validation(GMP/医药领域) | 常译"验证/确认" | 与软件工程口径不同,跨领域沟通需标明 |
| test case / test script / test suite | 测试用例 / 测试脚本 / 测试套件 | 用例是设计产物,脚本是实现产物,不可混用 |
| test condition | 测试条件 | "要测什么"的抽象描述,尚未成用例(对应 ISTQB 分析活动) |
| coverage | 覆盖率 | 必须附限定词(语句/分支/需求),单说"覆盖率"无意义 |
| exit criteria | 出口判据 | 不是"跑完所有用例",而是"达成约定条件" |
缺陷链:error(人犯错)→ fault/defect(制品中的瑕疵)→ failure(运行中失效)
注意:不是每个缺陷都会引发失效(触发条件未满足),这正是"跑过也可能漏"的原因之一。