第一版task配置
jacoco {
reportsDirectory = file("$buildDir/reports/jacoco")
}
task jacocoTestReport(type: JacocoReport,dependsOn: ["testDebugUnitTest","createDebugCoverageReport"]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for Debug build"
reports {
xml.enabled = true
html.enabled = true
}
def excludes = ['**/R.class',
'**/R$*.class',
'**/*$ViewBinder*.*',
'**/*$InjectAdapter*.*',
'**/*Injector*.*',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
// '**/*Activity*.*',
'**/CiMattersApplication*.*',
'android/**/*.*',
'**/di/']
// def debugTree = fileTree(
// dir: "${buildDir}/intermediates/app_classes/debug",
// excludes: excludes)
def kotlinDebugTree = fileTree(
dir: "${buildDir}/tmp/kotlin-classes/debug",
excludes: excludes)
// def mainSrc = "../app/src/main/java"
classDirectories.from = files(
// debugTree, kotlinDebugTree
kotlinDebugTree
)
sourceDirectories.from = files("${project.projectDir}/src/main/java")
executionData.from = files(dir: "$buildDir",includes:["/outputs/code-coverage/connected/*coverage.ec"])
doFirst {
new File("$buildDir/intermediates/app_classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
第二版task配置
task jacocoTestReport(type: JacocoReport) {
// dependsOn "testDebugUnitTest"
def lineList = new File(project.rootDir.toString() + '/settings.gradle').readLines()
def coverageCompName = []
for (i in lineList) {
if (!i.isEmpty() && i.contains('include')) {
coverageCompName.add(project.rootDir.toString() + '/' + i.split(':')[1].replace("'", '') + '/')
}
}
println coverageCompName
def coverageSourceCompName = []
for (i in lineList) {
if (!i.isEmpty() && i.contains('include')) {
coverageSourceCompName.add('../' + i.split(':')[1].replace("'", '') + '/')
}
}
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class',
'**/*Binding*.class',
'**/*BR*.class'
]
def coverageSourceDirs = []
for (i in coverageSourceCompName) {
def sourceDir = i + 'src/main/java'
coverageSourceDirs.add(sourceDir)
}
def coverageClassDirs = []
for (i in coverageCompName) {
def classDir = fileTree(dir: i + 'build/intermediates/javac/debug/classes', excludes: fileFilter)
coverageClassDirs.add(classDir)
}
def coverageKotlinClassDirs = []
for (i in coverageCompName) {
def classKotlinDir = fileTree(dir: i + 'build/tmp/kotlin-classes/debug', excludes: fileFilter)
coverageKotlinClassDirs.add(classKotlinDir)
}
classDirectories.from = files(coverageClassDirs, coverageKotlinClassDirs)
sourceDirectories.from = files(coverageSourceDirs)
// executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")
executionData.from = fileTree(dir: "$buildDir", includes: [
"outputs/code-coverage/debugAndroidTest/connected/*coverage.ec"
])
doFirst {
new File("$buildDir/intermediates/javac/debug/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
最后一版task配置---成功生成Java/kotlin的覆盖率
def coverageSourceDirs = [
'./src/main/java'
]
task jacocoTestReport(type: JacocoReport) {
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
reports {
xml.enabled = true
html.enabled = true
}
def allTrees = [
fileTree(
dir: './build/tmp/kotlin-classes/debug'
),
fileTree(
// 注意此处路径
dir: './build/intermediates/javac/debug/classes',
excludes: ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class'
])
]
classDirectories.from = allTrees
sourceDirectories.from = files(coverageSourceDirs)
// 注意此处路径
executionData.from = files("$buildDir/outputs/coverage.ec")
doFirst {
// 注意此处路径
new File("$buildDir/intermediates/javac/debug/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
第一版变更后,成功报告
task jacocoTestReport(type: JacocoReport) {
group = "Reporting"
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class',
'**/*Binding*.class',
'**/*BR*.class'
]
def debugTree = fileTree(
dir: "${buildDir}/intermediates/javac/debug/classes",
excludes: fileFilter)
def kotlinDebugTree = fileTree(
dir: "${buildDir}/tmp/kotlin-classes/debug")
classDirectories.from = files(
debugTree, kotlinDebugTree
)
sourceDirectories.from = files('./src/main/java')
executionData.from = fileTree(dir: "$buildDir", includes: [
"outputs/*coverage.ec"
])
doFirst {
new File("$buildDir/intermediates/javac/debug/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
task jacocoTestReport(type: JacocoReport) {
reports {
xml.enabled = true
html.enabled = true
}
def excludes = [
'**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class']
def debugTree = fileTree(
dir: "./build/intermediates/javac/debug/classes",
excludes: excludes)
def kotlinDebugTree = fileTree(
dir: "./build/tmp/kotlin-classes/debug")
classDirectories.from = files(
debugTree, kotlinDebugTree
)
sourceDirectories.from = files("./src/main/java")
executionData.from = files("$buildDir/outputs/coverage.ec")
doFirst {
new File("$buildDir/intermediates/javac/debug/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
反思:
1、关于Java/kotlin覆盖率路径
Java源码编译后是在javac目录下的,最初网上复制file路径时未对路径区分,直接照抄,判断上出了误差
2、关于report生成操作:
网上讲到的executionData对应的路径:/outputs/code-coverage/connected/*coverage.ec实际上是task createDebugAndroidTestCoverageReport生成的路径,且同时生成report;
我们用到的JacocoTestReport task,执行时executionData对应的路径实际是outputs目录下的coverage.ec
3、关于coverage.ec文件
看了很多自动化实现上传/手动上传,开始记忆错误,最初以为本地的文件上传之后,会自动更新,后来发现需要每次手动上传,把每次操作时的覆盖信息更新生成报告,后面操作需要注意下
4、第二版的jacocoTestReport task
基于settings.gradle的配置做筛选,是对组件化app的处理,暂时忽略该方法,对组件化app研究时再跟进。
网友评论