lecture 1
1、减少 faults 的自动化方法:静态分析 Static Analysis、测试 Testing、验证 Verification。
(1)静态分析法:通过扫描代码中的可疑模式来识别软件中的特定问题(例如,内存泄漏)
限制:(1)问题类型有限,(2)误报
(2)测试:将输入值输入到软件并运行它,以查看其行为是否符合预期
限制:(1)不可能覆盖所有可能的执行,(2)需要测试预言。
(3)验证:
形式验证:考虑所有可能的程序执行,并正式证明程序是否正确
限制:(1)很难有一个正式的规范,(2)大多数真实世界的程序因成本昂贵而无法证明
最广泛被应用的方法:测试。
2、为什么是“测试”被广泛应用?”why”
a) 测试 VS 代码评审::测试更加可靠。
b) 测试与静态检查相比:假阳性少,适用问题多。
c) 测试与正式验证相比:可扩展性更强,适用于更多的程序。正式验证更加耗时和困
难,但是不能找到测试找到的同样多的 bug。
d) 测试是线性回报,而其他的测试方法不是。
3、”how”测试方法概述:结构测试、数据流测试、随机测试、等价类测试、组
合测试
二、 PIE 模型
1、Fault, Error & Failure////故障、错误、失效
软件故障:软件中的静态缺陷(如缺陷 defect、bug 等)。可能导致系统或功能失效的异常
条件。
软件错误:不正确的内部状态,是某些故障的表现。计算、观察或测量值或条件,与真
实、规定或理论上正确的值或条件之间的差异。Error 是能够导致系统出现 Failure 的系
统内部状态。
软件失效:与需求或预期行为的其他描述相关的外部错误行为。当一个系统不能执行所
要求的功能时,即为 Failure,
Bug:故障/失效的非正式术语。informal term for fault/failure
三者之间的关系:由于人类试图通过上述 3 个基本术语来覆盖所有现实中的失效场景,所以
就有“Fault -> Error -> Failure”。即,故障发生了,会导致错误,错误有可能造成系统
功能的减弱或丧失
2、 PIE 模型
(1)基础概念 PIE 模型的三个关键词/三个必要条件
1) 执行/可达性 Execution/Reachability:必须到达程序中包含故障的位置。
使用户或测试人员观测到失效 failure 的过程
测试可能无法执行错误的位置!
2) 感染 Infection:程序状态必须是不正确的。
3) 传播 Propagation:受感染的状态必须传播,以导致程序的某些输出不正确。
错误的中间状态必须传播到最后输出,使得观测到的输出结果和预期结果不一致,即失效。
1)&2)--A test executing the fault may not produce an error!
执行含有故障的测试可能并不会产生错误。
1),2),3)- An error may not be propagated 传播 to the output!
有些代码不会触发到 fault。
产生 fault 的程序,有可能不会产生 error。
有的程序员,有 fault 和 error 也有可能不会导致 failure。
没有最终传播到输出得到失效,就无法判断有缺陷。缺陷寻找过程:failureerrorfaulit
三、Terminology 术语
1)
2)
3)
4)
5)
6)
test case 测试用例:测试输入(测试数据)、测试预言(期望的输出)、其他(环境)。
test oracle 测试预言:对于给定输入的软件的预期输出。测试用例的一部分。自动测试
中最难的问题:测试 oracle 生成。
test fixture 测试夹具:测试执行所需要的固定环境。被测软件的固定状态,作为运行测
试的基线;也称为测试上下文,例如,用一组特定的已知数据加载数据库、输入数据准
备和设置/创建假对象或模拟对象。
test suite 测试套件 & test script 测试脚本
Test suite 测试套件:
测试用例的集合。通常这些用例共享类似的先决条件和配置。可以按顺序一起
运行。
不同的测试套件用于不同的目的。(特定的平台、特定的功能、性能……)
Test script 测试脚本
自动运行一系列测试用例或测试套件的脚本。
test driver 测试驱动程序
一个软件框架,它可以加载一组测试用例或测试套件。
它还可以处理预期输出和实际输出之间的配置和比较。
test adequacy 测试充分性:充分性标准:一个规则,它让我们判断一组测试数据对于一
个软件的充分性。
不能总是使用所有的测试输入,那么我们应该使用哪一个,什么时候停止?
我们需要一个策略来确定我们什么时候做得足够多
测试充分性实例:测试覆盖率。评估代码测试百分比的度量方法:语句覆盖、分支覆盖
1、测试和调试的区别 Testing vs. Debugging
测试:为了发现 bug。通过执行测试和观察失效 failure。
调试:修复 bug。通过定位、理解和纠正故障 fault。
2、Verification vs. Validation 确认/核实和批准的区别
批准 Validation
确保产品、服务或系统满足客户和其他确定的涉众的需求。它通常涉及接受和适合外部客户。
我们正在开发正确的产品吗?
核实/确认 Verification
对产品、服务或系统是否符合规定、要求、规范或附加条件的评估。这通常是一个内部过程。
我们生产的产品是对的吗?
3、静态测试与动态测试 Static Testing vs. Dynamic Testing
静态测试:不执行程序;
动态测试:执行程序。
4、黑盒测试与白盒测试 Black-box Testing vs. White-box Testing
黑盒测试:不需要源代码
白盒测试:需要源代码。
灰盒测试器部分地知道内部结构,包括访问内部数据结构的文档和使用的算法。(白盒+黑
盒)
5、测试水平
system 系统测试、integration 集成测试、module 模块测试、unit 单元测试、其他未命名测试
6、V 模型和测试级别/水平的对照:
6、测试过程
四、Fault Revisit 缺陷审视
1、Definitions of Bug bug 的定义
发现 fault、error--困难
通过预言和输出的对比发现失效 failure -容易
2、怎么确认一个故障 fault:
故障 fault 是由修复 fixing 定义的!最小修复次数
3、哪一个是故障?
故障是由测试定义的!
一个故障还是两个故障?
lecture 2 单元测试
1、Granularity of Testing 测试粒度
单元测试 Unit testing:对每个模块进行测试。
集成测试 Integration Testing:测试模块之间的交互 Test the interaction between modules。
系统测试:由开发人员对整个系统进行测试。
验收测试 Acceptance Testing:没有正式测试用例的客户根据用户需求验证系统。
2、单元测试:
测试软件的一个基本模块,例如:一个函数,一个类,一个组件。
显示的典型的问题:
局部数据结构、算法、边界条件、错误处理。
3、为什么要做单元测试?
• Divide-and-conquer approach 分而治之的方法
Split system into units 将系统分为多个单元。
•
• Debug unit individually 单独调试单元
• Narrow down places where bugs can be 缩小 bug 可能出现的范围
• Don’t want to chase down bugs in other units 不想追踪其他单元的 bug
4、怎么做单元测试?
分层构建系统:从不依赖于其他类的类开始。继续在已经测试的类上进行测试。
好处:
避免编写模拟类 Avoid having to write mock classes。
当测试一个模块时,它所依赖的模块是可靠的。
图片是什么意思?是:如果按照 1234 的顺序进行测试是可以的,但是如果想按照 3412,就
是类 3 先测试,就会因为类 3 依赖于类 1,2 而有问题,这是就需要编写模拟类
5、Unit test framework 单元测试框架
xUnit。由 Kent Beck 于 1989 年创建,正是这个人发明了 XP 和 TDD。第一个是 sUnit(用
于 smalltalk)
Junit。最流行的 xUnit 框架。对应的语言大约有 70 个 xUnit 框架
6、传统的测试
直接用值调用要测试的函数。要重复编写很多调用函数。
解决方法:
通过测试程序自动验证、可以自己编写这样的测试程序,或者使用测试工具支持,比如
Junit。
Junit:一个简单、灵活、易用、开源、实用的 Java 单元测试框架。能够处理大量的测试用
例。
7、测试套件:一组测试(或其他测试套件)。将测试组织成更大的测试集,帮助自动化测试。
lecture 3 白盒测试 Whitebox Testing
白盒测试:在有源代码的条件下进行测试。单元测试就是白盒测试;但是如果转换为执行程
序,也可能变为黑盒测试。
一、测试中的图
1、控制流图 Control Flow Graph
2、图的来源:源代码、需求规格说明、有限状态机 Finite State Machine、用例图、活动图、
3、图的形式定义 Formal Definition of Graphs
图 G(V,E)。
V: 有限的非空节点集合。V={v1,v2,v3,v4}。
E:边的集合(顶点对) E={(v1,v2), (v1,v3), (v2,v4), (v3,v4)}。
V0:一组初始节点 initial vertices,V0={v1}。Vf:一组最终节点 final vertices,Vf={v4}。
V0,Vf 是 V 的子集。
4、问题:单个节点也是图。边集合 E 不能是无限集合,E 也是有限集合。
多个初识节点、终止节点
4、路径 path:顶点序列– [v1,v2, …,vn]。每对顶点都是一条边。
(1)路径长度:路径上所包含的边的数量。单顶点的路径的长度为 0。
(2)子路径:p 中顶点的子序列。
(3)测试路径 test path:从初始顶点开始,到终止顶点结束的路径。
测试路径表示测试用例的执行。
一些测试路径可以被许多测试执行。如何表示?有多个测试都会执行这条路径,
找到>=2 的测试用例即可
有些测试路径不会被任何测试执行。怎么证明?某一条测试路径没有任何测试
可以实现。
(4)测试和测试路径
path(t):测试 t 执行的测试路径。一个测试路径
path (T):测试集 T 执行的一组测试路径。测试路径的集合
每个测试只执行一个测试路径
二、图覆盖标准 Graph Coverage Criteria
1、可达性 reach
v1 可达 v2:存在一条路径,以 v1 为起点,以 v2 为终点。
v1 可达图 G: '如果存在一条路径从 v1 开始,以 G '中的一个顶点结束
2、语法可达与语义可达
语法可达 Syntactic reach:图中存在的一条路径。
语义可达 Semantic reach:存在一个可以执行该路径的测试。
在测试时,要保证所有代码语义可达。
节点代表语句,边表示转向(例如 if)
3、覆盖 cover
如果顶点 v 在路径 p 上,测试路径 p 覆盖这个顶点 v。
如果边 e 在 p 中,则测试路径 p 覆盖这条边 e。
如果子路径 p’在 p 中,测试路径 p 覆盖子路径 p’。
4、图覆盖 Graph Coverage
使用图的测试:以图形式开发软件模型;要求测
试覆盖特定的顶点集、边或子路径。
5、结构覆盖(率)Structural Coverage
定义在一个图上只是根据顶点和边
1) 源代码
2) 需求规格说明
3) 设计图
6、数据流覆盖 Data Flow Coverage
要求用对变量的引用对图表进行注释。
7、测试标准/测试准则 Test Criteria
测试需求(TR) Test Requirements:描述测试路径的属性。
测试标准/准则 Test Criterion:定义测试需求 Test Requirements 的规则
满意度:/满足 Satisfaction: 给定一个准则 C 的测试需求集 TR,当且仅当 TR 中的每个
测试需求在路径(T)中有一个测试路径满足测试需求 TR 时,图上的一组测试 T 满足准
则 C。
三、结构化覆盖 Structural Coverage
1、节点覆盖 Vertex Coverage (VC)
测试集 T 满足图 G 上的顶点覆盖当且仅当对于 v 中的每个语法可达顶点 v,在路径(T)中有一
个路径 p,使得 p 覆盖 v。(将所有的节点都覆盖的用例)
TR 包含 G 中的每个可达顶点。
2、边缘覆盖(率)Edge Coverage (EC)
当且仅当对于边集 E 中的每一条语法可达边 e,在路径(T)中都有一条路径 p,使得 p 覆盖 e
时,测试集 T 满足图 G 上的边缘覆盖。(将所有的边都覆盖的测试集)
TR 包含 G 中每个可到达的边。
3、节点覆盖与边缘覆盖