目录
自制Ekstazi 1
1. 缘起 1
2. 论文理解 1
1. 依赖格式 2
2. 分析(A)阶段 2
3. 执行(E)阶段 3
4. 收集(C)阶段 3
5. 非调试校验和 3
3. 项目结构&原理讲解 3
自制Ekstazi
1.缘起
在自动化测试这门课程中,我学习到了有关源码级测试、移动端测试、智能软件测试的知识,并且对源码级测试产生了浓厚的兴趣。我们知道,回归测试是当今自动化测试研究的热门重点之一,项目中平均80%的测试成本都用在了回归测试中。而自动化回归测试技术包含了测试用例优先级技术、测试用例选择技术等。而在其中,测试用例选择技术又涵盖了静态测试用例选择和动态测试用例选择,其中静态是仅仅通过根据代码的分析来判断类之间的依赖关系,而动态则是通过运行来获得类之间的依赖关系。经过研究发现,动态在总体上是要优于静态的,因为它可以更精准地获得依赖关系,而静态可能会分析过头,反而导致效率降低。但是在运行测试阶段,静态是优于动态的,因为静态不用像动态那样反复插桩,效率较高。除此以外,在细粒度和粗粒度的选择上,Java测试粒度选择偏向于类级别的。
在工具复现大作业中,我选择了复现一种几年前研究人员提出的动态自动化测试用例选择技术Ekstazi,并且尝试加入了自己的理解。凑巧的是,我的一位舍友选择了静态自动化测试用例选择技术Starts,这样我们就可以对彼此复现的工具进行相互的评估,比较静态和动态的差别。
具体资料(.jar文件、论文、PPT、录屏等)都在content文件夹中。
2.论文理解
我阅读了Ekstazi: Lightweight Test Selection 这篇介绍了Ekstazi的论文,对其产生了较为深刻的理解。以下为我通过论文对Ekstazi的一些简单的理解。
Ekstazi是一种轻量级的回归测试选择工具,它可以很好地与测试框架和构建系统集成。Ekstazi跟踪文件上测试的动态依赖关系,并且不需要与版本控制系统集成。
Ekstazi是基于构建系统的最新进展,以及之前类依赖性和外部资源来工作的。与以往大多数基于更细粒度依赖关系(例如,方法或基本块)的测试用例选择技术不同,Ekstazi不需要与版本控制系统集成,它没有明确地比较旧版本和新版本;相反,它为每个测试类计算其所依赖的文件,这些文件可以是可执行代码(例如,Java中的.class文件)或外部资源(例如,配置文件)。如果测试类的相关文件没有任何更改,则不需要在新版本中运行这个测试类。
Ekstazi有三种方式可以调用,一种的通过maven集成,一种是通过ant集成,最后一种是通过程序调用来使用。程序调用的三个接口如下:
org.ekstazi.Ekstazi.inst().checkIfAffected("name")
org.ekstazi.Ekstazi.inst().startCollectingDependencies("name")
org.ekstazi.Ekstazi.inst().finishCollectingDependencies("name")
接下来简单解析一下Ekstazi的工作原理。
典型的测试用例选择技术有三个阶段:分析(A)阶段选择在当前版本中运行哪些测试用例,执行(E)阶段运行所选测试,收集(C)阶段为下一个版本收集信息。而Ekstazi在文件的级别上收集依赖关系。接下来首先介绍Ekstazi存储依赖项的格式。其次提供关于每个阶段的更多细节及其与测试框架的集成。最后描述Ekstazi中一个重要的优化方法。
1.依赖格式
Ekstazi以一种简单的格式存储依赖关系,这种格式类似于Fabricate构建工具的依赖关系格式。对于每个测试类,Ekstazi存储该类在执行期间使用的文件的名称和校验和。校验和是散列出的文件的内容。这些校验和能让Ekstazi在不去检查旧版本的情况下也能发现文件修改。Ekstazi将所有信息存储在每个测试类的单独依赖项文件中。
2.分析(A)阶段
Ekstazi的分析阶段非常简单,因此速度也很快。对于每个测试类,Ekstazi将检查所有依赖文件的校验和是否仍然相同。如果是这样,则不选择运行这个测试类。这种检查不需要对旧版本和新版本进行复杂的比较。事实上,它甚至不需要分析旧版本(就像构建系统只要知道哪些源文件更改就可以增量编译代码一样)。
Ekstazi自然地处理新添加的测试类:如果某些类没有依赖项信息,它将被选中运行。最初,在Ekstazi的第一次运行时,没有任何类的依赖信息,所以它们都被选中运行了。
3.执行(E)阶段
Ekstazi首先决定不运行哪些测试类。这就避免了准备运行一个类并发现它不应该运行而导致的不必要的开销(例如,加载类或生成一个新的JVM)。A阶段将排除不应该运行的测试类的列表,并且构建系统在执行测试之前忽略它们。
有两种可能的方法可以集成E阶段和C阶段。第一个也是最简单的方法是一次性完成回归测试。显然,未选择中的测试类的依赖项无法更改。但是,需要运行所选的测试类,并确定它们是否仍然通过或失败,然后通知启动测试会话的用户。又因为这些类的依赖关系发生了变化,所以更新它们的依赖关系文件的是最简单的方法。但是,收集依赖关系会有一个开销。因此,一些设置可能允许使用两种模式:一种是不收集依赖项,只是为了确定测试结果并尽快通知用户;另一种是为了收集依赖项,但是效率可能会差一些。
4.收集(C)阶段
收集阶段将为已执行的测试类创建依赖项文件。Ekstazi监视测试和被测试代码的执行情况,以收集在每个类的执行期间访问的文件集,计算这些文件的校验和,并将它们存储在相应的依赖文件中。
为了精确地收集已访问的文件,Ekstazi动态地分析字节码并监视执行,以收集显式访问的文件和隐式访问的文件。在执行过程中,Ekstazi会持续收集类加载器中加载过的类,这些类将有可能写入测试类的依赖关系。
5.非调试校验和
Ekstazi使用文件校验和提供了几个优点,最显著的是旧版本无需用于A阶段,而且哈希计算校验和的速度很快。基本方法从整个文件内容中计算校验和,包括所有的字节码。在计算校验和时,Ekstazi可以忽略某些文件部分,如编译时注释和其他调试信息。
以上便是我对Ekstazi的简要理解,这些都是基于论文得出的。显然,这其中有一些功能点是我暂时无法实现的(比如执行时的多JVM环境,我暂时无法搭建;分析配置文件和测试类的依赖关系,实话实说,这个我也不是很会),还有一些功能点,我希望把它们做的更加对用户友好一些,因此做了一些简单的修改,除此以外,我还在自己的代码中加入了一些其他功能。