背景


在项目周期中,每一次代码提交、版本升级都会发生代码变更,而这些变更对QA来说往往是后知后觉的且无序的,它可以是某代码行的变更也可以是某一个方法的添加、某一类文件的添加,当我们写service层的单测case时,经常是根据service方法而进行的,那么我们是否可以知道这些变更属于那些方法呢,这些方法有没有被case覆盖到呢?
答案是肯定的,我们能够找到变更的归属,并且通过case本身对于生产代码的依赖找到方法覆盖,进而推断出哪些生产代码需要增加CASE。

 

怎么去做?

 

 

首先我们需要维护一个本地代码版本(可称之为历史版本),当每次拿到最新代码时都与本地代码版本作一下比较,那么就能得出变更结果了。貌似很简单的,对吧!我们用diff做吗??no,diff的方式不能帮我们找到方法,我们需要设计一个java源码比对算法。将java源码抽象出语法树,并在词基础上进行比对,这样就能得出方法变更了。最后一个问题,我们怎样拿到测试case覆盖的生产方法?通常我们在写case的时候在会写xxx接口.xxx方法,并以此来run生产代码,因此会产生一个从case到生产代码的依赖,而这个依赖就是我们case对生产方法的覆盖了。
下面就来介绍一下基于以上思路实现的工具xmonitor,用来结合checkin_build来监控生产代码测试覆盖的的小东西。


Xmonitor设计思路


Xmonitor会维护一个本地代码仓库,被启动时将检查线上代码库与本地维护的代码(历史版本)是否一样,如果发生变更则去找出变更了的方法,并判定这些变更的方法是否被测试CASE(service的单测CASE)覆盖到。当然也可以用它找出当前版本中所有的没有被case覆盖到的生产方法和已经被覆盖到的生产方法。
从开发的模块上分为五个部分,获取CASE依赖、获取最新版本代码、抽取测试覆盖方法、抽取生产代码方法、获取测试覆盖/未覆盖,见下图:
 



目录结构说明:

 


1.bin目录下存放sh文件:
getDiffRes.sh:调度java文件比对模块,完成工程下所有java文件方法抽取,并根据旧版本代码内容生成变更方法List.
createDependencyXML.sh:调度第三方工具[dependencyFinder]捕获测试CASE覆盖到的生产方法。
compareJavaCode.sh :调度代码比对模块是生成最新的代码变更生产代码中的方法。
2.lib目录下存放jar包,用于java程序执行:
CompareJavaCode.jar:完成新旧版本java文件对比,生成变更方法记录、接口-实现类关系。
CreateXmonitorXML.jar:生成xml格式的最终结果{此次变更中未覆盖的生产方法、此次变更中已覆盖的方法、所有代码中未覆盖的方法、所有代码中已覆盖的方法}。
GenNoCovModifyMethod.jar:引入测试CASE依赖信息、变更方法、接口-实现类关系,进行逻辑运算,生成各种情况下的覆盖/未覆盖生产方法列表。
3.conf目录下存放配置:di2ACC.conf、blacklist.dat
di2ACC.conf:工具依赖配置。
blacklistofnocover.dat、blacklistofcovered.dat:测试未覆盖、已覆盖过滤条件,对最后产出结果进行过滤。
注:默认过滤action包、bo包下的set、get方法,可以通过修改文件内容调整过滤条件。
3.Utils:工具函数目录,存放文件:Empty.java,getNoDuplicat.sh
getNoDuplicat.sh:结合blacklist.dat文件进行结果过滤。
Empty.java:一个空的java文件,协助生成java代码对比变更。
4.Data目录:程序运行中产出的各种结果文件。
5.Logs目录:用于存放日志,目前未开发独立的日志功能,试用期间以重定向的方式写Log.
6.main.sh:xmonitor工作主程序,完成对其他工作模块调度。


获取工具:

 

 

请参照wiki直接下载。


工具使用:


准备条件
1. 工具运行依赖条件:
a) 需要运行在执行checkin_build的hudson服务器上。一般来说在hudson服务器上都会有svn客户端、编译结果class等。
b) 需要安装jdk1.6。
2. 运行工具要做的事情:
a) 下载crm-xmonitor包到执行服务器上,并解压缩。
b) 在工具目录下找到conf/di2ACC.conf,并修改配置。


如何配置:


di2ACC.conf配置文件中共有三种类型的配置项:项目本身的配置、运行环境配置、工具运行时临时文件配置。由于项目之间的差异(表现在项目名、项目svn路径、测试用例编译前后目录、生产代码编译前后目录)

第一部分:项目svn路径、项目名称、测试/生产代码编译前后路径


 

Svnrootdir与Svnnewtag:前者是当前项目在svn服务器上的根路径,后者是当前项目的名称;两者拼成字符串时用于下载项目源码。
SRC_BIN、QATEST_BIN、RDTEST_BIN:前者是项目最新代码在checkin_bulid任务中编译完成的生产代码class路径,后两者主分别为QA、RD各自的测试用例编译class。程序将根据这些class信息寻找依赖关系,找到测试覆盖。
注:SRC_BIN路径主要了辅助帮助查找散落在生产代码目录内的测试用例。
PRO_SRC、QATEST_SRC、RDTEST_SRC:前者是checkin_bulid任务中获取的项目最新生产代码,后两者分别为QA、RD各自的测试用例。该配置用于找到测试用例。
第二部分:jdk依赖目录

第三部分:程序运行时内部变量




启动模式:


工具有两种工作模式,其区别在作用范围不同,第一种作用范围为当前项目,产出所有本项目当前版本中所有未覆盖、已覆盖的生产方法。并根据版本差异中的代码变更情况抽取出属于此次引起的未覆盖、已覆盖。
启动工具命令(有all参数):Sh –x main.sh all >logs/xmoitor.log

另一种工作模式作用范围为此次变更,产出此次变更未覆盖的生产方法、已覆盖的生产方法。由于需要进行新旧版本对比,所以必须是在初次运行之后才能使用该模式,否则会由于没有历史版本作为参考,导致工具运行失败。因此,工具初始运行不能选用该模式。
启动工具命令(无参数):Sh –x main.sh >logs/xmonitor.log
程序执行完毕后会将结果分别以文本文件、XML两种格式输出到out文件夹中。
文本文件名为:updatenocoverprodcode.dat、updatecoveredprodcode.dat、allcoveredprodcode.dat、allnocoverprodcode.dat, 分别表示此次更新中测试未覆盖的生产代码,此次更新中已测试覆盖的生产代码;当前前项目中测试未覆盖的生产代码,当前前项目中已测试覆盖的生产代码。
XML格式文件名为xmonitor.xml包括所有输出内容,四个标签囊括了四个文本文件的内容,当文本文件不存在时,XML对应标签内容为空。


结束语

 

 

到这里本文基本上就结束了,限于笔者的编码水平,代码写的比较ugly,后面会持续进行优化,敬请期待。


【参考文献】*
1. 开源工具DependencyFinder, http://depfind.sourceforge.net/.

 作者:kzhao