1. 介绍
变更影响分析(change impact analysis)提供了对一系列程序变更的语义影响的反馈。
这篇文章针对面向对象编程语言进行分析,小的变更会有意想不到的结果:如,向现有类添加方法会影响整个程序虚拟方法的调用
本文的方法:
- 将源代码的变更映射到一组原子变更(使用类、方法、域和它们的相互关系作为变更的原子单元)
- 此外还确定了这些原子变更的偏序关系,这些变更间的偏序关系保证程序句法合法
- 给定一系列原子变更 A \mathcal{A} A和给定的测试驱动集合 T \mathcal{T} T,执行程序的部分功能
静态分析来确定:
- 测试驱动 T \mathcal{T} T中挑选被变更 A \mathcal{A} A影响子集 T ′ \mathcal{T'} T′用于回归测试
- 变更集合 A \mathcal{A} A的子集 A ′ \mathcal{A'} A′可能影响 T \mathcal{T} T中的某些测试驱动 t \mathcal{t} t。这允许开发者忽略不被测试 t \mathcal{t} t失败影响的变更
- 变更 A \mathcal{A} A的子集可能不影响任何测试用例,这些变更可以立即纳入
- 覆盖率信息可以作为创建新测试用例的基础
2. 动机样例
贴了一页论文(-_-|||,太长不看)
该样例包含5个类:Course, Person, Professor, Student和University
然后有3个测试驱动:
- TestA:找到特定教授打印TA教授的课
- TestB:打印大学所有人员
- TestC:找到特定学生打印其学分
然后就是说了三个方面的对于代码的变更
3. 变更
规定源程序为 P P P,修改后的程序为 P ′ \mathcal{P'} P′,他们都语法正确且可编译。
3.1 原子变更
方法的一个关键是将源代码的编辑转换为一组原子变化
这些原子变更有两个重要特征:
- 粒度与分析内容相符合,也就是说,如果用了更细粒度的原子变更概念,分析也不会产生更精确的结果
- 任何源代码的编辑可以分解为唯一的原子变更集合
CM捕获对方法体的任意改变,包括:
- 在之前的抽象方法中添加方法体
- 从非抽象方法中删除方法体,让它抽象
- 方法体中任何语句级别的变更
LC类别对影响动态dispatch行为的源代码变更进行抽象,它可能由添加或删除方法,添加或删除集成关系导致。
change impact analysis 会忽略某些类型的源代码级别的变更,这些变更除了控制可见性外没有语义影响,如修改类/方法/域的修饰符,增删注释和增删import语句。
3.2 影响方法dispatch的变更
方法dispatch可能受多种编辑影响,我们使用 l o o k u p lookup lookup形式化方法dispatch过程。 l o o k u p lookup lookup 接受两个参数:运行时类型和静态方法调用,返回通过virtual dispatch机制调用的方法定义
3.3 对原子变更排序
变更可能收到语法和语义上的其他变化。本文仅考虑必须满足的语法依赖性以保证可编译。语法依赖的例子有不能扩展未定义的类,或调用为定义的方法。语义依赖的例子是新增方法 m m m仅在存在被调用的方法 m ′ m' m′的改编版本时才表现出正确的行为。
使用原子变更上的偏序关系 ≺ \prec ≺表示语法依赖(同时也定义了传递闭包 ⪯ ∗ \preceq^* ⪯∗), ≺ \prec ≺定义了 A \mathcal{A} A的consistent子集 A ′ \mathcal{A'} A′,使得 A ′ \mathcal{A'} A′应用到 P P P的结果是合法的程序 P ′ ′ P'' P′′。
A
′
\mathcal{A'}
A′是consistent满足的条件:
∀
a
′
∈
A
such that
a
′
⪯
∗
a
,
a
∈
A
′
⇒
a
′
∈
A
′
\forall a'\in A\text{ such that }a'\preceq^*a, a\in A'\Rightarrow a'\in A'
∀a′∈A such that a′⪯∗a,a∈A′⇒a′∈A′
计算这些东西需要确定原子变更中引用的程序片段的语法要求
3.4 导出原子变更
将源代码编辑分解为原子变更是很简单直接的,文章由于篇幅原因只通过一个例子展示过程
4. 变更影响分析
程序 P P P有一些列测试驱动 T = t 1 , … , t n \mathcal{T}=t_1, \dots, t_n T=t1,…,tn, N o d e s ( P , t i ) Nodes(P, t_i) Nodes(P,ti)表示程序 P P P执行测试驱动 t i t_i ti经过的方法结点, E d g e s ( P , t i ) Edges(P,t_i) Edges(P,ti)为调用关系。方法间的调用关系可以形式化地表示为: A . m → C B . n A.m\rightarrow_CB.n A.m→CB.n,表示 A . m A.m A.m通过类型 C C C对象的方法 n n n调用了方法 B . m B.m B.m
A f f e c t e d T e s t s ( T , A ) \mathit{AffectedTests(\mathcal{T}, \mathcal{A})} AffectedTests(T,A)和 A f f e c t e d C h a n g e s ( t , A ) \mathit{AffectedChanges(\mathcal{t}, \mathcal{A})} AffectedChanges(t,A)可以用来回归测试和故障定位,具体方法如下:
- 任何不在 A f f e c t e d T e s t s ( T , A ) \mathit{AffectedTests(\mathcal{T}, \mathcal{A})} AffectedTests(T,A)中的测试驱动在 A \mathcal{A} A前后必定产生相同执行结果,所以只需要重新运行 A f f e c t e d T e s t s \mathit{AffectedTests} AffectedTests中受影响的测试驱动就行
- A f f e c t e d C h a n g e s ( t , A ) \mathit{AffectedChanges(\mathcal{t}, \mathcal{A})} AffectedChanges(t,A)可以识别没有影响任何测试驱动的改变,这些改变可以安全的包含(纳入)。有时候这样的改变也是暗示缺少了测试用例
- A f f e c t e d C h a n g e s ( t , A ) \mathit{AffectedChanges(\mathcal{t}, \mathcal{A})} AffectedChanges(t,A)可以在测试失败时提供有用的信息
7. 未来工作
- 从源代码编辑中导出原子变化
- 计算原子变更间的序