android 代码覆盖率
背景
项目使用的是small插件。一个app分为main和多个插件,为了统计插件的代码覆盖率。
1 修改插件
修改插件build.gradle
buildTypes {
release {
...
}
debug{
minifyEnabled false
testCoverageEnabled = true //打开debug版本的代码覆盖率开关
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
因为工程原因插件生成的classes文件在下次生成的时候会变动。因此要讲classes文件拷贝到其他位置暂存。
tasks.whenTaskAdded { task ->
if (task.name == 'assembleRelease' || task.name == 'assembleDebug') {
task.doLast {
println "copy classes to jacoco"
def applicationId = android.defaultConfig.applicationId
def artifactName = applicationId.substring(applicationId.lastIndexOf(".") + 1, applicationId.length())
project.copy {
from "build/intermediates/classes/debug"
into "${rootDir}/../jacoco/${artifactName}/classes/debug"
}
}
}
}
2 修改main
main作为插件的容器,我们的测试代码也在这里。所有的测试用例继承于BaseTest.
给BaseTest的finishZ增加覆盖率保存功能。
@Override
protected void finished(Description description) {
super.finished(description);
.....
generateEcFile(true);
} /**
* 生成ec文件
*
* @param isNew 是否重新创建ec文件
*/
public static void generateEcFile(boolean isNew) { SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd_HHmmss");
final String DEFAULT_COVERAGE_FILE_PATH = "/sdcard/coverage/" + String.format("coverage_%s.ec", df.format(new Date()));
LogUtils.i("生成覆盖率文件: " + DEFAULT_COVERAGE_FILE_PATH);
OutputStream out = null;
File mCoverageFilePath = new File(DEFAULT_COVERAGE_FILE_PATH);
try {
if (isNew && mCoverageFilePath.exists()) {
LogUtils.i("JacocoUtils_generateEcFile: 清除旧的ec文件");
mCoverageFilePath.delete();
}
if (!mCoverageFilePath.exists()) {
File d = new File("/sdcard/coverage/");
d.mkdirs();
mCoverageFilePath.createNewFile();
}
out = new FileOutputStream(mCoverageFilePath.getPath(), true); Object agent = Class.forName("org.jacoco.agent.rt.RT")
.getMethod("getAgent")
.invoke(null); out.write((byte[]) agent.getClass().getMethod("getExecutionData", boolean.class)
.invoke(agent, false)); } catch (Exception e) {
LogUtils.i("generateEcFile: " + e.getMessage());
} finally {
if (out == null)
return;
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
编译main,生成测试apk和debug版本的apk.
3.测试
使用测试系统进行测试
4.收集所有测试被测收集的测试数据。
import subprocess
import os,sys o = subprocess.check_output(['adb','devices'])
ls = o.split('\n')
for line in ls:
if line.endswith('device'):
id_ = line.split('\t')[0]
os.makedirs('./report/'+id_)
c1 = ['adb','-s',id_,'pull','/sdcard/coverage','./report/'+id_]
print ' '.join( c1 )
o1 = subprocess.check_output(c1)
print o1
5.建立新的gradle工程,生成报告。
新建文件夹jacocReport。
进入文件夹运行gradle init。
修改build.gradle
apply plugin: 'jacoco'
buildscript {
repositories {
mavenLocal()
mavenCenter()
maven { url 'plugins' }
}
dependencies {
classpath 'net.researchgate:gradle-release:2.4.1'
classpath 'com.android.tools.build:gradle:2.2.3'
}
}
allprojects {
repositories {
mavenLocal()
mavenCenter()
flatDir {
dirs 'libs'
}
}
}
//首先先删除旧的merge结果文件
task removeOldMergeEc(type: Delete) {
delete "${rootDir}/../jacoco/coverageMerged/mergedcoverage.ec"
}
task mergeReport(type:JacocoMerge,dependsOn:removeOldMergeEc){
group = "Reporting"
description = "merge jacoco report."
destinationFile= file("${rootDir}/../jacoco/coverageMerged/mergedcoverage.ec")
//这里的ec_dir是存储ec文件的文件夹
FileTree tree = fileTree("$projectDir/../jacoco/report") {
include '**/*.ec'
}
def cnt =0
tree.each{
cnt++
}
println "ec file conut:"+cnt
// tree.each{f->println f}
executionData = tree //executionData(files)
}
["plugin1",'plugin2'].each { it1->
task "Report$it1"(type: JacocoReport,dependsOn: [mergeReport]) {it ->
println "I'm task $it"
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
def pluginName1 = "$it1"
println pluginName1
reports {
xml.enabled = true
html.enabled = true
}
classDirectories = fileTree(
dir: "${rootDir}/../jacoco/${pluginName1}/classes/debug",
excludes: ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class'
])
def coverageSourceDirs =[
//不需要代码路径
]
sourceDirectories = files(coverageSourceDirs)
File f = new File("${rootDir}/../jacoco/coverageMerged/mergedcoverage.ec")
println ""+f.exists()
println "" + f.length()+ " bytes"
executionData = files("${rootDir}/../jacoco/coverageMerged/mergedcoverage.ec")
doFirst {
//修改claess 文件
println "${rootDir}/../jacoco/${pluginName1}/classes/debug"
new File("${rootDir}/../jacoco/${pluginName1}/classes/debug").eachFileRecurse { file ->
if (file.name.contains('$$')) {
println "modify " + file.name
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
}
task allReport(dependsOn: [Reportplugin1,Reportplugin2]){
doLast{
println "done!"
}
}
最后上目录
.
├── main #主apk代码的目录
├── jacoco #数据目录-存放ec文件,classes文件
├── jacocoReport #生成报告的工程目录 build.gradle在此
├── plugin1 #插件1
├── plugin2 #插件2
android 代码覆盖率的更多相关文章
- Android自动化测试探索(五)代码覆盖率统计
Android 代码覆盖率统计 本周开始准备统计Android自动化用例的代码覆盖率,将最终使用的方法记录下来. 覆盖率监测的原理 覆盖率监测的原理跟iOS上的原理差不多,大致的思路参考下吧, iOS ...
- Jenkins构建Android项目持续集成之单元测试及代码覆盖率
单元测试 在软件开发中一直在推崇TDD(测试驱动开发),但是一直不能被有效的执行或者并不是真正的测试驱动开发(先开发后写单元测试),因为我们懒!而Android开发又是大多应用层面的开发,很多都是和视 ...
- Android自动化测试探索(七)代码覆盖率统计
之前在 https://www.cnblogs.com/zhouxihi/p/11453738.html 这篇写了一种统计Android覆盖率的方式 但是对于一些比较复杂或者代码结构不够规范的项目,有 ...
- 安卓代码覆盖率:android studio+ gradle+jacoco
在工程的oncreate()方法添加如下代码,目的是创建ec文件. String DEFAULT_COVERAGE_FILE_PATH = "/mnt/sdcard/coverage.ec& ...
- 测试代码覆盖率工具学习(Android Emma)
博客分类: 工具分享 eclipseeclemmaemmatestng 关于eclemma的历史和怎么安装,请参考http://www.ibm.com/developerworks/cn/ ...
- Android源码目录结构详解(转载)
转自:http://blog.csdn.net/xiangjai/article/details/9012387 在学习Android的过程中,学习写应用还好,一开始不用管太多代码,直接调用函数就可以 ...
- android源码的目录结构
android源码的目录结构 [以下网络摘抄] |-- Makefile ! l/ a5 n% S% @- `0 d# z# a$ P4 V3 o7 R|-- bionic ...
- Android 4.0 源代码结构
Android源码的第一级目录结构 Android/abi (abi相关代码.ABI:application binary interface,应用程序二进制接口) Android/bioni ...
- Android源码-学习随笔
在线代码网站1:http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/ 书籍: ...
随机推荐
- 破解navicat
每次试用版也真的是烦,注册机试过一次后,又提示注册 果断选择其他方法 官网先下载一个正版 再下patchNavicat.exe 安装完navicat后直接点击patchNavicat 选择navica ...
- JSP/Servlet Web 学习笔记 DayFour
Servlet概述 Servelt是使用Java Servlet应用程序接口及相关类和方法的Java程序. Servlet是用Java编写的Server端程序,它与协议和平台无关.Servlet运行于 ...
- 软工实践 - 第十五次作业 Alpha 冲刺 (6/10)
队名:起床一起肝活队 组长博客:https://www.cnblogs.com/dawnduck/p/10004469.html 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过 ...
- urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed解决办法
描述 今天学习写一篇用python(我的是Python 3.6)登录知乎网(https://www.zhihu.com) 的爬虫,测试时报错:urlopen error [SSL: CERTIFICA ...
- 201621123033 《Java程序设计》第9周学习总结
第九次作业 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 //stream(),filter(),collect() ...
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)
A.The game of Osho(sg函数+二项展开) 题意: 一共有G个子游戏,一个子游戏有Bi, Ni两个数字.两名玩家开始玩游戏,每名玩家从N中减去B的任意幂次的数,直到不能操作判定为输.问 ...
- BZOJ2535 [Noi2010]Plane 航空管制 【贪心 + 堆】
题目链接 BZOJ2535 题解 航班之间的关系形成了一个拓扑图 而且航班若要合法,应尽量早出发 所以我们逆拓扑序选点,能在后面出发的尽量后面出发,不会使其它点变得更劣,容易知是正确的 第二问只需枚举 ...
- VS MFC 改变AfxMessageBox标题 AFX_IDS_APP_TITLE
其实这个标题在资源String Table里就能找到,查找AFX_IDS_APP_TITLE,在这里你就能轻而易举的改变标题了. 注意:有的工程的资源String Table里面没有添加AFX_IDS ...
- Golang/Go语言/Go IDE/Go windows环境搭建/Go自动提示编译器/GoSublime
Go是Google开发的一种编译型,并发型,并具有垃圾回收功能的编程语言. 罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pike)及肯·汤普逊于2007年9月开始设计Go ...
- 网站开发只需数小时?Meteor 说这才是未来
原文: http://www.geekpark.net/topics/211573/ 那个想要挑战过去数十年沿用至今的网站开发模式的新势力来了. Meteor 是从 YC 孵化而出的现代网站开发平台, ...