核心主题: 软件测试设计技术入门 - 所有工程师都应掌握的最重要的测试技术。
主要内容分解:
-
软件测试是什么?
- 定义: 软件质量保证(QA)的一种手段。
- 目的: 确认软件的行为符合工程师的预期(即,验证软件是否按设计工作)。
- 核心挑战: “完美的测试是不可能的”。测试的目标是尽可能多地发现缺陷(Bug)。
-
软件测试的分类(示例):
- 单元测试: 测试最小单位(如单个方法、模块)。
- 集成测试: 测试多个单元组合在一起后的交互。
- UI/系统测试: 测试集成了数据库、用户界面等组件的整个系统。
-
软件测试技术是什么?为什么需要?
- 问题: 理论上测试用例越多越可靠,但现实中无法执行所有可能的测试。
- 目的: 这些技术是为了在有限的测试用例下,最大程度地发现缺陷而存在的知识和手段。
- 核心价值: 帮助将测试用例数量减少到现实可执行的水平,同时通过优化设计来保证质量。测试技术是手段,而非最终目的。
- 目标: 找到“最优”的测试用例集。
-
重要的软件测试技术(列举):
- 同值类测试 / 等价类划分
- 边界值测试
- 领域分析测试
- 决策表测试
- 配对组合测试 / 成对测试 / 正交测试
- 状态迁移测试
-
软件测试的基本思路:
- 覆盖性: 尽量减少遗漏。
- 精确打击: 对可疑区域进行重点测试。
- 如何找到可疑区域?
① 间、逆、类推、外侧:思考中间值、相反情况、类似情况、边界之外的情况。② 意地悪な条件:考虑恶意或异常的条件输入。③ 当たり前を疑う:质疑那些看起来理所当然的事情。
-
测试设计方法(Approach):
- 基于契约的测试: 只关注满足方法前置条件(正常调用所需条件)的输入范围。
- 防御性测试: 不仅测试前置条件范围内的输入,也测试范围外的、异常的输入。
- 关键点: 在项目/模块中需要明确采用哪种方法!
-
核心测试技术详解:
- 同值类测试 / 等价类划分:
- 概念: “同值类”是指对于测试目的而言具有相同意义的一组输入值(例如,所有正数、所有负数、空值)。
- 方法: 每个同值类中选取一个典型值进行测试(因为该类的其他值预期行为相同)。
- 边界值测试:
- 概念: 测试同值类的边界点及其紧邻的上、下值。
- 依据: 缺陷经常隐藏在边界值附近。
- 示例: 范围
1 <= x <= 10,测试点:0, 1, 10, 11。
- 领域分析测试:
- 适用场景: 当多个输入条件之间存在相互作用时。
- 关键点:
On:边界上的值。Off:边界外紧邻的值(在开区间一侧)。In:有效域内部的值。Out:有效域外部的值。
- 方法: 构造“领域测试矩阵”。通常,测试一个条件时,将其设置为
On或Off点,而将其他条件设置为In点。矩阵的每一列可以对应一个测试用例,非常实用。 - 与边界值关系: 边界值测试可视为专注于
On和Off点的领域分析测试。
- 决策表测试:
- 适用场景: 当有多个条件通过逻辑表达式(如 AND, OR)组合在一起决定结果时。
- 问题: 条件组合数量随条件数指数增长(2^条件数)。
- 方法: 列出所有条件及其可能的取值(真/假),列出所有可能的组合及其对应的预期动作(规则)。可以尝试压缩规则(如条件有优先级时)。
- 配对组合测试 / 成对测试 / 正交测试:
- 核心思想: 并非测试所有可能的组合(数量太大),而是测试所有条件对(Pair) 的组合覆盖。
- 依据: 大部分缺陷(70-85%)是“单模式缺陷”(单个条件/模块出错)或“双模式缺陷”(两个条件/模块组合出错)。
- 方法: 使用正交表(预先设计好的表格)或工具(如 PICT)来生成覆盖所有两两组合的最小测试用例集。
- 步骤: ① 列出条件和取值。 ② 确定每个条件的取值数量。 ③ 选择合适的正交表(或使用工具)。 ④ 将条件映射到正交表。
- 优点: 显著减少测试用例数量。
- 注意点: 对于特别重要或易出错的组合,仍需额外增加测试用例。
- 状态迁移测试:
- 适用场景: 测试基于当前状态和事件会导致行为变化的系统(如工作流、协议、状态机)。
- 工具: 状态迁移图(状态、迁移/事件、动作)、状态迁移表(状态 vs 事件 -> 下一状态/动作)。
- 基本覆盖: 测试所有迁移路径(这会自然覆盖所有状态)。
- 关键点: 测试无效事件(N/A - Not Applicable)的处理(防御性测试)。状态迁移表有助于发现规格说明的遗漏。
- 高级覆盖: N-切换覆盖
- 关系矩阵: 表示状态间迁移(行:前状态,列:后状态,元素:事件)。
- 1-切换覆盖: 测试所有长度为1的迁移序列(即所有直接迁移)。关系矩阵本身。
- 2-切换覆盖: 测试所有长度为2的迁移序列(A->B->C)。计算关系矩阵的平方。
- N-切换覆盖: 测试所有长度为N的迁移序列。计算关系矩阵的(N+1)次方。用于测试涉及多个中间状态的复杂路径。
- 同值类测试 / 等价类划分:
-
覆盖率(Code Coverage):
- 测试类型关联:
- 黑盒测试: 仅根据规格说明设计测试用例,不查看内部代码。
- 白盒测试: 根据内部代码逻辑设计测试用例(需要访问代码)。
- 数据流测试: 检查变量的“定义(生成)-> 使用 -> 消亡”过程是否正确。现代IDE/静态分析工具常涵盖。
- 控制流测试: 度量代码中的执行路径被覆盖的程度。核心是覆盖率指标。
- 覆盖率级别(按严格程度递增):
- 语句覆盖 / 行覆盖 (C0): 执行过的代码行数占总可执行行的百分比。最基础。
- 判定覆盖 / 分支覆盖 (C1): 每个判定(如
if,while的条件表达式整体)的真/假分支都被执行过的百分比。100% C1 意味着 100% C0。注意: 将组合条件(如A && B)视为一个整体判定。 - 条件覆盖 (C2): 每个判定中的每个原子条件(如
A,B)的真/假值都被独立测试过的百分比。不一定保证 100% C1 或 C0。 - 多条件覆盖 (MCC): 测试每个判定中所有原子条件的所有可能真假组合。用例数 = 2^(条件数),通常过多。
- 修正条件/判定覆盖 (MC/DC): 在保证 100% C1 和 C0 的前提下,用少于 MCC 的用例数达到条件组合覆盖。要求每个条件都能独立影响判定结果。常用于安全关键系统标准。
- 覆盖率测量: 使用专门的覆盖率工具(如 JaCoCo for Java, Coverage.py for Python)。
- 重要注意事项(警告!):
- 高覆盖率 ≠ 高质量/无缺陷: 无法检测逻辑错误(如错误的边界值计算)、遗漏代码(未实现的功能)、特定数据错误(如除零)。
- 收益递减: 覆盖率越高,达到更高百分比所需的成本和精力通常越大,而发现的缺陷可能越少。追求100%通常不经济。
- 避免目标偏移: 覆盖率是评估测试充分性的手段,本身不是目的。不要为了数字而测试。
- 测试类型关联:
-
实际测试设计要点与建议:
- 设计流程: 首先基于测试技术设计测试用例 -> 然后使用覆盖率评估测试是否足够充分。
- 覆盖率目标:
- 85% 左右的语句覆盖率常被视为一个现实的“努力目标”。
- Google 将 85% 语句覆盖率作为参考基准。
- 语言差异:动态类型语言(Python, JS)通常需要比静态类型语言(Java, C#)更高的覆盖率来弥补编译期检查的缺失。
- 务实策略: 对于非关键任务软件,在达到合理覆盖率后,结合用户反馈来发现剩余缺陷也是一种可行策略。
- 终极目标: 始终牢记测试的最终目的是通过发现缺陷来提升软件质量,而软件质量本身又是服务于业务成功的手段。不要迷失在技术细节中。
-
参考资料(文中提及):
- Udemy 课程链接:
https://www.udemy.com/course/software-test-design/ - Django 单元测试指南:
https://nwpct1.hatenablog.com/entry/how-to-write-unittest-on-django - PICT 工具介绍:
https://qiita.com/bremen/items/6eceddc534d87fc797cc#:~:text=%E3%80%8CPICT%EF%BC%88Pairwise%20Independent%20Combinatorial%20Testing,%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%EF%BC%88MIT%20License%EF%BC%89%E3%81%A7%E3%81%99%E3%80%82(日文,介绍这个微软出品的配对组合测试工具)
- Udemy 课程链接: