Designers are more efficient and effective if they can raise their level of abstraction.
1. Overview
1.1. Fault, Error和Failure
- Software Fault: 软件中的静态缺陷。
- Error是程序运行时的错误状态,例如pc错误,返回值错误,执行路径不同,遍历数组的索引错误等。
- Software Error: 由fault导致的不正确的内部状态,例如外部不可见的内部变量和程序预期的不一致,但输出可能仍正确。
- 有时执行了Fault的语句时,也不一定会进入Error状态。例如fault来自于循环的迭代判断语句,但由于循环提前终结,该语句不一定会感染程序。
- Software Failure: 相对于软件需求或预期行为描述来说,外部可见的,不正确的行为。
- 有的时候进入Error状态也不一定会导致failure。例如输出正确,但是遗漏了一些语句没有执行。
bug通常包含上述了三种情况。
1.2. 测试的目标
- 验证(Verification) 判断软件开发过程中某个阶段的产品是否满足上一阶段建立的要求。由specification约束。
- 确认(Validation) 在软件开发结束前评估软件是否符合目标用例。有可能软件满足spec(即通过verification),但不符合用户需求(用例),则validation失败。
- IV&V(independent Verification & Validation)
1.3. 软件测试基础
- Testing: 通过观察程序执行评估软件
- Test Failure:测试的执行导致程序failure
- Debugging:给出failure寻找fault的过程
1.3.1. fault/failure模型(或称RIPR模型)
测试用例的设计应当能够满足下面四个条件
- Reachability: 测试应当能够到达程序中fault处。
- Infection:程序应当能够进入错误state,揭露fault的能力。
- Propagation:可传播性,被感染的状态传播到输出。
- Revealability:可揭露性,测试者能够观察到错误输出。
1.4. 软件测试活动
- 设计测试输入
- 产生测试用例
- 运行测试脚本
- 分析结果
- 向开发者报告结果
1.5. 测试级别
- Acceptance Testing: 从需求和用例的角度,需要领域知识
- System Testing: 从架构设计角度,整个系统是否达到规范的要求
- Integration Testing:从子系统设计角度,通过接口访问模块
- Module Testing:从细节设计角度
- Unit Testing:从实现角度
- Regression testing
软件测试级别和软件开发活动的对应如下图:
- 需求分析:获取顾客需求。
- 架构设计:选择系统组件以实现整个系统。
- 子系统设计:明确子系统的结构和行为。
- 细节设计:定义单个模块(C中的一个文件,C++或Java中的一个类)。的结构和行为。
- 实现:实际生成代码的阶段。
不同级别的测试的主要区别在于它们希望揭露的fault的类型。面向对象开发范式中模块测试和单元测试相同。
1.6. 覆盖准则
事实上,基本不可能通过穷尽整个输入空间来测试程序。覆盖准则给出了如何从输入空间获取测试用例以及需要设计多少测试用例的解决方案。
测试集合的设计以满足覆盖准则为目标,当测试集合满足覆盖准则时,测试者应当对程序的程序性有所预计,特别是:
- 输入空间很多边界情况已经被考虑到
- 测试具有很低的重叠率
针对不同架构可能有不同的覆盖准则,但是它们一般都能归纳为以下4种数学结构:
- input domains
- graphs
- logic expressions
- syntax descriptions
基于这种抽象模型的测试被称为Model-Driven Test Design process(MDTD)。
1.7. MDTD
测试工作主要包括4部分:
- 测试设计:设计能够有效测试程序的输入值,下面两种应当互补
- criteria-based: 基于工程目标设计测试用例,例如设计目标是满足覆盖准则
- human-based: 基于领域知识设计
- 测试自动化
- 测试执行
- 测试评估
整个测试过程及分工被描述成下面的过程:
如上,首先要获取软件构建(可以是源程序、UML图、自然语言描述或用户手册)。criteria based的测试设计者通过它们构建程序的抽象模型(以input domain,graph,logic expressions,或syntax description的形式)。
接着,基于工程目标的测试设计者将抽象模型对应的覆盖准则用于创建测试需求。human-based的测试设计者基于领域知识创建测试需求。这两种需求会被精化成测试规范(test specification)。例如,若使用了边覆盖,测试需求会明确必须包含图中的哪一条边。一个精化的测试规范会描述图中的一条完整路径。之后就从design abstraction level进入implementation abstraction level。
1.8. 基于准则的测试设计
1.8.1. 覆盖准则的定义
覆盖准则的例子:
- 覆盖所有分支(分支覆盖)=> 每个分支生成两个tr,true和false
- 覆盖所有方法至少一次(调用覆盖)=> 每个方法生成一个tr
- Test Requirement: A test requirement is a specific element of a software artifact that a test case must satisfy or cover.
- Coverage Criterion: A coverage criterion is a rule or collection of rules that impose test requirements on a test set.
- Coverage: Given a set of test requirements TR for a coverage criterion C, a test set T satisfies C if and only if for every test requirement tr in TR, at least one test t in T exists such that t satisfies tr.
- Minimal Test Set: : Given a set of test requirements TR and a test set T that satisfies all test requirements, T is minimal if removing any single test from T will cause T to no longer satisfy all test requirements.
- Minimum Test Set: : Given a set of test requirements TR and a test set T that satisfies all test requirements, T is minimum if there is no smaller set of tests that also satisfies all test requirements.
- Coverage Level: Given a set of test requirements TR and a test set T, the coverage level is the ratio of the number of test requirements satisfied by T to the size of TR. TR中被T满足的比例。
- Criteria Subsumption: A coverage criterion C1 subsumes C2 if and only if every test set that satisfies criterion C1 also satisfies C2.
无法被满足的需求被称为infeasible。意味着不存在满足该测试需求的测试值。
- generator:生成用于满足准则的值
- recognizer:覆盖分析工具
有两种方式满足让C1准则subsume C2准则:
- C1的测试需求构成C2需求的超集。
- 例如:C1需求为{1,2},C2需求为{1}
- 两种准则的测试需求之间存在多对一或一对一的情况。
- 例如:C1需求为{A,B},C2需求为{1},存在映射f: {A->1,B->1}(满足A的都满足1,满足B的都满足2)
- 例如:满足覆盖所有分支的也满足覆盖所有语句
1.8.2. infeasibility和sumsumption
有的时候会出现如果C1不存在infeasible test的情况下,C1能够subsump C2.但是如果出现了infeasible test,C1就无法包含C2.但是这种情况在实际测试过程中通常可以忽略。
2. reference
- Introduction to Software Testing 2nd Edition