课程预习资料来源:https://www.icourse163.org/learn/NJU-1001773008?tid=1450627499#/
预习
软件测试基础
PIE 模型
概念辨析:
- Fault:程序中存在的静态错误(编程过程中产生)
- Error:程序因运行到其中的 Fault(s) 而进入的错误的中间状态(程序运行时产生)
- Failure:Error(s) 传播到程序外部,使得用户观测到与预期不符的错误行为(程序行为完成时产生)
PIE 模型:
- Execution/Reachability:程序中含有 fault 的地方必须被执行到
- Infection:程序必须进入错误的中间状态(error)
- Propagation:被感染的状态必须传播到程序外部,即导致程序错误的输出结果(产生 failure)
针对 PIE 模型的分析:
- 测试不一定能执行到带有 fault 的语句
- 测试执行到带有 fault 的语句,不一定会触发 error
- 测试执行到带有 fault 的语句并触发 error,不一定会产生 failure
软件测试术语
测试用例(test case):
- 测试输入(test input):test data
- 测试预言(test oracle):expected output
- 其他(others):environment
测试(testing):执行测试并观测 failure(发现 bug)
调试(debugging):定位、理解并改正 fault(修复 bug)
确认(validation):确认规格文档是否与用户需求相符
确认(verification):确认最终实现是否满足规格文档
静态测试(static testing):不运行程序
动态测试(dynamic testing):运行程序
黑盒测试(black-box testing):不需要源代码
白盒测试(white-box testing):需要源代码
灰盒测试(gray-box testing):通过反编译等手段获得了部分结构信息
测试过程:
白盒测试
测试中的图
测试路径:从初始节点到终结节点的一条路径(可以通过设定哑节点使初始节点和终结节点唯一)
测试路径代表了测试用例的执行情况(有些路径可以被多个测试用例执行到,有些路径不可被执行到)
path( t ) 表示测试 t 执行的测试路径;path( T ) 表示测试集合 T 执行的测试路径集合
本课程不考虑非确定性环境,即认为一个测试用例只能执行到一条测试路径
图覆盖准则
语法可达(Syntactic reach):通过语法构建的图中存在一条路径
语义可达(Semantic reach):存在能够被执行到的测试路径
覆盖(Cover):
- 如果节点 v 在测试路径 p 中,则该测试路径 p 覆盖节点 v
- 如果边 e 在测试路径 p 中,则该测试路径 p 覆盖边 e
- 如果子路径 p’ 在测试路径 p 中,则该测试路径 p 覆盖子路径 p’
测试需求(Test Requirement):描述测试路径性质
测试准则(Test Criterion):描述测试需求的规则
给定一个测试准则 C,派生出对应的测试需求集 TR,定义一个测试用例集 T 满足 C,当且仅当对于 TR 中的每个测试需求,集合 path( T ) 中都存在一条测试路径满足该测试需求
结构化覆盖
顶点覆盖;边覆盖;边对覆盖(字面意思)
n-路径覆盖:为了定义的完整性,要求长度覆盖小于等于 n 的所有路径
蕴含(Subsume):
结构化覆盖的例子:
控制流测试
将程序按照一定的粒度(语句、语句块、函数、模块)转换为控制流图
使用 Soot 为 Java 程序自动生成控制流图
数据流测试
关于数据流的几个定义:
数据流覆盖准则:
定义覆盖;引用覆盖;定义引用路径覆盖
JUNIT 使用示例
Maven 中的配置信息:
黑盒测试
随机测试
随机测试(模糊测试)
自适应随机测试
反随机测试(应对离散的输入域)
等价类划分
将输入域划分为一系列子集(等价类),在每个子集中选取有代表性的测试用例进行测试
划分准则:不同类型数据的处理;不同的数据流或控制流;合法或非法输入
等价类划分需要满足完备性和无冗余性
边界值分析
(字面意思)
组合测试
完全组合测试:组合数等于各输入等价类个数的乘积,测试代价高
两两组合测试:覆盖任意两个测试变量之间所有的取值组合(可以推广到 T-wise combinatorial test)
功能测试
功能测试简介
功能测试常用步骤:
- 根据需求细分功能点
- 根据功能点派生测试需求
- 根据测试需求设计功能测试用例
- 逐项执行功能测试用例验证产品
探索式测试
探索式测试是一种软件测试风格
强调独立测试人员的个人职责和自由
将测试学习、设计、执行、结果分析作为相互支持的活动
在整个项目中并行地执行
强调:关注价值、风险驱动
性能测试
简介
度量方法:
- 服务端性能采用 CPU、内存等使用率来度量
- 客户端性能通常根据系统处理特定用户请求的响应时间来度量
响应时间 = 服务端响应时间 + 客户端响应时间
并发用户数(取决于测试对象的目标业务场景)
吞吐量:单位时间内处理的用户请求数量
负载测试:验证系统在正常的负载条件下的行为
压力测试:评估系统处于或超过预期负载时的行为
移动应用测试
简介
Android 测试工具:
- Monkey
- Android Instrumentation
- Android BDD-Calabash
众包测试:
自动化测试
一些测试思想:
模糊测试:通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法
变异测试:在细节方面改进程序源代码的软件测试方法。这些所谓的变异,是基于良好定义的变异操作,这些操作或者是模拟典型应用错误(例如:使用错误的操作符或者变量名字),或者是强制产生有效地测试(例如使得每个表达式都等于0)。目的是帮助测试者发现有效地测试,或者定位测试数据的弱点,或者是在执行中很少(或从不)使用的代码的弱点。
蜕变测试:用来缓解“测试准则问题”的软件测试技术。 测试准则是一种让测试人员判定程序是否能通过测试的机制。当测试人员对于所选择的测试用例难以确定预期的正确结果,或无法判定程序输出是否满足预期的结果时,便认为存在“测试准则问题”。
差分测试:通过将同一测试用例运行到一系列相似功能的应用中观察执行差异来检测 bug
一些已有的研究成果:
- 自动化测试脚本修复
- 测试用例推荐
- 基于互联网群体 智能的软件测试
- 智能软件测试
- 众包协作:一棵Bug报告树的生长
- 面向群体智能的测试报告自动化分析
- 面向群体智能的Bug截屏文本自动生成
- 基于截图理解的测试回放技术
- 基于深度图像理 解的报告排序
- 基于多源信息语义关联的众测报告半监督聚类
- 基于强化学习和图像理解的跨平台测试技术
- 面向群体智能的测试自动回放
变异测试
背景
变异测试的产生:
模拟缺陷,量化缺陷检测能力,指示测试有效性
模拟:变异产生错误版本,模拟探测 bug 的过程
量化:变异得分(变异杀死率)
变异体:基于语法变换规则,通过对源程序进行程序变换得到的一系列变体(假设源程序不包含缺陷;假设变异体表达了某种缺陷)
变异得分:变异测试对测试套件检错能力的量化(变异体杀死率)
变异体的分类:有效;夭折(编译不通过);冗余(等价、重复、蕴含)
变异算子:
一系列语法变换规则
变异的依据,反应了测试人员关注的缺陷种类
基本形式
- 对程序源码进行变换
- 对程序编译结果(中间表示)进行变换
- 元变异
基础假设:
- 缺陷是简单的、可模拟的
- 缺陷是可叠加的
- 缺陷检测是有效的
过程
变异体筛选:对变异体进行筛选;对变异算子进行筛选(研究方向:变异算子的定义与约减策略)
变异体生成:将选中的变异算子实例化(研究方向:元变异,基于字节码操作,热替换)
变异体优化:
- 识别等价变异体:代码优化 / 数据流分析
- 识别冗余变异体:操作符角度 / 缺陷层级角度 / 程序分析角度
变异体执行:变异测试过程中最昂贵的阶段
研究内容:针对计算变异得分(场景A)/ 计算变异矩阵(场景B)优化执行过程
优化策略
- 改变测试用例顺序(A)
- 匹配测试用例与变异体(A)
- 避免执行必定存活的变异体(A, B)
- 限定变异体的执行时间(A, B)
变异得分计算:(研究内容:变异杀死的条件,测试预言的生成)
应用
评估作用:变异得分评估测试充分性
引导作用:利用变异测试 / 分析结果引导测试过程
传统应用:应用于确定性系统
- 测试生成
- 语言生成
- 测试优化
- debug 引导
变异 & AI:应用于非确定性系统
总结
模糊测试
起源与发展
模糊测试的诞生:
由字符乱码能够导致程序崩溃的现象启发,为提高 UINX 系统的可靠性,以随机字符串作为输入,运行操作系统组件,观察是否发生崩溃
近期发展:
概念与架构
初始构想:工具(模糊器 Fuzzer) + 目标(待测程序 PUT) + 循环(执行程序 ⇆ 崩溃分派)
相关术语:
- 模糊:从模糊输入空间得到输入来执行 DUT 的过程
- 模糊测试:应用模糊过程来验证 DUT 是否违反正确性策略的测试技术
- 模糊器:用于实现模糊测试的程序(核心,需要完成输入生成、测试执行和输出分析)
- 模糊运动:Fuzzer 按照特定的 Correctness Policy 在给定 DUT 上的一次具体的执行
- 缺陷预言:用于确定一次给定执行是否违反具体 Correctness Policy 的程序
- 模糊配置:控制和描述模糊(测试)算法的数据和约束
- 种子输入:在模糊测试过程中为输入生成提供基准的测试输入
模糊测试框架:
家族与分类
模糊测试家族:
- AFL家族(C/C++):AFL、AFLFast、AFLSmart、AFLNet、 AFLGo、AFLIoT、FairFuzz、Mopt.、Neuzz
- LibFuzzer家族(C/C++):LibFuzzer、Entropic
- JQF家族(Java):JQF、BeDivFuzz、CONFETTI
- 其他(Rust、Python等):Angora、DeepXplore
模糊测试分类:
按照采用的运行时信息:
- 黑盒:仅从输入输出着手优化,利用输入格式或输出状态引导测试,效率高但有效性欠缺
- 白盒:使用混合分析、污点分析等昂贵白盒分析技术进行优化,利用详细程序分析结果引导测试,有效行高但效率低适配性差
- 灰盒:使用轻量级插桩监控程序,执行时收集各类信息并以此引导测试,黑盒白盒 trade-off
按照输入生成的策略:
- 基于变异:本质上是将种子输入转换为比特串进行变换,易于泛化但容易破环输入结构
- 基于生成:本质上是利用给定/挖掘/学习得到的文法规则来构建结构化输入,适用于对输入结构性要求较高的场景,但需要人工赋予一定的领域知识
按照引导过程:
- Search-based:将测试转化为搜索问题,以代码覆盖率作为指示器、以启发式算法为核心,将测试导向更高覆盖的方向
- Gradient-based:将测试转化为优化问题,以最大化缺陷发掘输入为目标构建目标函数,梯度下降算法迭代求最优解(若缺陷离散且无法预知,则将目标退阶为代码覆盖)
按照测试的目的:
- 定向:针对程序中的某个目标位置进行快而有效的测试
- 非定向:验证程序的正确性,检测程序中潜在的缺陷
按照应用领域:网络协议、Compiler、DNN、IoT、内核
按照优化角度:种子调度、变异策略、能量调度、过程建模
iSE模糊测试
移动应用测试
众包测试
自动化测试
人为驱动的测试行为转化为机器执行
提升效率、降低成本、快速回归测试、保证测试一致性
开发时间周期长、对测试人员要求高、脚本维护开销大
adb 捕获移动应用内部状态
Appium
代码摘要
代码摘要:翻译任务;特殊的文本摘要
研究目的:为缺少注释的旧代码补上注释;为新代码自动化生成注释
潜在应用场景:代码理解;代码审核;代码定位
早期工作:本文检索,从代码中提取关键词进行组合
中期工作:分析已有工作的有效性(提取的关键词和程序员实际认为的关键词是否相符等问题)并提出优化方案
近期工作:数据驱动,深度学习模型
测试:
- 黑盒,白盒,灰盒
- 单元,集成,系统
- 功能,性能,安全,
- 正向:等价类划分(组合,正交实验设计)
- 负向:故障假设(边界值,…)
Bug:
- 显性
- 隐性
智能系统
图
软件分析 -> 代码的图结构
随机:自适应随机
- AI for SE
- SE for AI