覆盖率是衡量测试质量的一个指标,但在版本高速迭代的互联网应用中,单纯通过代码覆盖率的数值是无法体现测试实际覆盖的问题,尤其是版本之间的 diff,而且研发也并不会仔细的去看每行代码的覆盖.所以有了覆盖率与 git diff 结合的想法,通过查看功能测试中版本代码变更的部分是否覆盖,更高效的利用覆盖率,保证变更功能被测试覆盖
覆盖率使用的 jacoco 关于 jacoco 手工测试生成:
根据 q 博的方式略做了修改,在应用中加了隐藏开关,并在退出应用时统计覆盖率并上传到服务器.这里用的是 ftp,虽然有点过时,但还算方便~
代码很简单,就不贴了.
jacoco 的生成需要对应的 class 文件,所以需要在编译打包时将 class 文件上传
dependencies {
ftpAntTask("org.apache.ant:ant-commons-net:1.8.4") {
module("commons-net:commons-net:1.4.1") {
dependencies "oro:oro:2.0.8:jar"
}
}
}
def remotedir = "Class/" //ftp目录
//def hostname = "10.0.100.210"
def hostname = "10.0.0.243"
def username = "uftp"
def password = "111111"
task uploadFTP << {
//上传至FTP
remotedir += innerVersion
ant {
taskdef(name: 'ftp',
classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
classpath: configurations.ftpAntTask.asPath)
ftp(server: hostname,
userid: username,
password: password,
remotedir: remotedir,
action: 'mkdir')
ftp(server: hostname,
userid: username,
password: password,
remotedir: remotedir) {
fileset(dir: "./build/intermediates/classes") {
}
}
}
}
首先在 job 里添加了三个可选参数,用于选择新旧版本以及分支
构建时进行 jacoco 文件的合并和报告的生成,并调用我写的 java 程序改造报告.
# generate jacoco report
gradle jacocoMerge --stacktrace
gradle jacocoTestReport
# generate final report
java -jar ~/work/gitdiff.jar -r $OldVersion $NewVersion -j build/reports/jacoco/jacocoTestReport/html -p src/main/java
cp -r ~/work/.resources build/reports/jacoco/jacocoTestReport/
在程序中调用 git diff, 并对结果进行解析
public HashMap<String,FileDiff> parseGitDiff()
{
HashMap<String,FileDiff> fileMap=new HashMap<String,FileDiff>();
ArrayList<String> curFile=new ArrayList<String>();
for (int i = 0; i < diffList.size(); i++) {
curFile.add(diffList.get(i));
if((i+1)==diffList.size()||diffList.get(i+1).startsWith(GIT_FLAG))
{
FileDiff diff=new FileDiff(curFile);
fileMap.put(diff.getId(), diff);
curFile=new ArrayList<String>();
}
}
return fileMap;
}
public ArrayList<LineDiff> parseLineDiff(ArrayList<String> files)
{
ArrayList<LineDiff> diff=new ArrayList<LineDiff>();
boolean isStart=false;
String frontLine="";
for (int i = 0; i < block.size(); i++) {
String line=block.get(i);
if((i+1)<block.size()&&block.get(i+1).startsWith(MINUS_FLAG)&&!isStart)
{
isStart=true;
frontLine=block.get(i);
}
if(line.startsWith(MINUS_FLAG)&&isStart)
{
LineDiff lineDiff=new LineDiff(frontLine, line,LineDiff.Type.Minus);
diff.add(lineDiff);
}
if(i>1&&!block.get(i-1).startsWith(MINUS_FLAG)&&!line.startsWith(MINUS_FLAG))
{
frontLine=block.get(i-1);
isStart=false;
}
if(line.startsWith(PLUS_FLAG))
{
LineDiff lineDiff=new LineDiff(frontLine,line,LineDiff.Type.Plus);
diff.add(lineDiff);
}
}
return diff;
}
代码写的不太好,能力强的同学可以忽略~
将 git diff 提取出来后找到对应覆盖率 html 并写入.从而产生了一个只有代码变更文件的 list
效果:
然后更改 jacoco 原来的 prettify.js 文件,对变更代码进行标记
function showDef (defLine) {
var beginLine = defLine[0].substring(1);
var between = defLine[1];
var target = document.getElementsByClassName('linenums')[3];
var defDom = document.createElement('div');
var beginDom = target.getElementsByTagName('li')[beginLine - 1];
with(defDom.style){
position = 'absolute';
left = '9px';
top = beginDom.offsetTop + 16 + 'px';
backgroundColor = '#0f0';
opacity = '.3';
width = '40px';
height = 15 * between + 'px';
};
defDom.id = 'def' + beginLine;
document.documentElement.appendChild(defDom);
}
对变更代码进行跳转
function showDefLine () {
var content = window['CONTENT'];
var def = content.match(/@@(.*[^@@])/g);
for (var i = def.length - 1; i >= 0; i--) {
var _def = def[i].replace(/@@/g, '').split(' ');
showDef(_def[2].split(','));
};
var sourceDom = document.getElementsByClassName('linenums')[1];
sourceDom = sourceDom.getElementsByTagName('span');
for (var i = sourceDom.length - 1; i >= 0; i--) {
if(sourceDom[i].innerHTML === '@@'){
sourceDom[i].parentNode.onclick = function () {
document.body.scrollTop = document.getElementById('def' + this.getElementsByTagName('span')[9].innerHTML).offsetTop - 100;
}
}
};
}
修改后的效果如下,页面 top 显示 diff 代码
左侧绿色标记 diff 代码
最后,写的很匆忙,有点乱,勿怪~