前言
覆盖率是衡量测试质量的一个指标,但在版本高速迭代的互联网应用中,单纯通过代码覆盖率的数值是无法体现测试实际覆盖的问题,尤其是版本之间的diff,而且研发也并不会仔细的去看每行代码的覆盖.所以有了覆盖率与git diff结合的想法,通过查看功能测试中版本代码变更的部分是否覆盖,更高效的利用覆盖率,保证变更功能被测试覆盖
覆盖率的收集
覆盖率使用的jacoco 关于jacoco手工测试生成:
Android 手工测试代码覆盖率增强版
根据q博的方式略做了修改,在应用中加了隐藏开关,并在退出应用时统计覆盖率并上传到服务器.这里用的是ftp,虽然有点过时,但还算方便~
代码很简单,就不贴了.
class文件的收集
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") { } } } } |
在jenkins上覆盖率报告生成
首先在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代码
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。