JaCoCo 不适用于 Robolectric 测试
JaCoCo doesn't work with Robolectric tests
我想在我的 android 项目中为我的 JUnit 测试生成代码覆盖率报告,所以我添加了 JaCoCo gradle 插件。这是我的项目级别 build.gradle
文件:
apply plugin: 'jacoco'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-beta6'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
subprojects { prj ->
apply plugin: 'jacoco'
jacoco {
toolVersion '0.7.6.201602180812'
}
task jacocoReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
group = 'Reporting'
description = 'Generate Jacoco coverage reports after running tests.'
reports {
xml {
enabled = true
destination "${prj.buildDir}/reports/jacoco/jacoco.xml"
}
html {
enabled = true
destination "${prj.buildDir}/reports/jacoco"
}
}
classDirectories = fileTree(
dir: 'build/intermediates/classes/debug',
excludes: [
'**/R*.class',
'**/BuildConfig*',
'**/*$$*'
]
)
sourceDirectories = files('src/main/java')
executionData = files('build/jacoco/testDebugUnitTest.exec')
doFirst {
files('build/intermediates/classes/debug').getFiles().each { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
}
jacoco {
toolVersion '0.7.6.201602180812'
}
task jacocoFullReport(type: JacocoReport, group: 'Coverage reports') {
group = 'Reporting'
description = 'Generates an aggregate report from all subprojects'
//noinspection GrUnresolvedAccess
dependsOn(subprojects.jacocoReport)
additionalSourceDirs = project.files(subprojects.jacocoReport.sourceDirectories)
sourceDirectories = project.files(subprojects.jacocoReport.sourceDirectories)
classDirectories = project.files(subprojects.jacocoReport.classDirectories)
executionData = project.files(subprojects.jacocoReport.executionData)
reports {
xml {
enabled = true
destination "${buildDir}/reports/jacoco/full/jacoco.xml"
}
html {
enabled = true
destination "${buildDir}/reports/jacoco/full"
}
}
doFirst {
//noinspection GroovyAssignabilityCheck
executionData = files(executionData.findAll { it.exists() })
}
}
运行宁 ./gradlew jacocoFullReport
效果很好。但不幸的是,运行 和 RobolectricTestRunner
的测试未报告覆盖率(在测试中明显调用的指令未报告为已覆盖)。没有 @RunWith
注释或 运行 且 MockitoJUnitTestRunner
的测试报告覆盖率很好。
如能解决此问题,我们将不胜感激。
更新 1: 我注意到我应该使用 RobolectricGradleTestRunner
。但是没有用。
可能的解决方法是已知问题 - https://github.com/jacoco/jacoco/pull/288
或者将jacoco版本降级到0.7.1.201405082137
更新
不再需要解决方法。您必须使用 gradle 版本 2.13
和 jacoco 版本 0.7.6.201602180812
.
更新根 build.gradle
:
buildscript {
dependencies {
classpath 'org.jacoco:org.jacoco.core:0.7.6.201602180812'
}
}
task wrapper( type: Wrapper ) {
gradleVersion = '2.13'
}
运行 ./gradlew wrapper
更新项目build.gradle
:
apply plugin: 'jacoco'
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
我遇到了同样的问题,但现在按照此 link、
解决了我的问题
问题link:https://github.com/robolectric/robolectric/issues/2230
这里提到了这个问题的解决方案:
我遇到了同样的问题。我更改了 jacoco 插件版本并添加了 includenolocationclasses 属性。这是工作 jacoco.gradle 文件(我正在使用 gradle 包装器 2.14.1):
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.6.201602180812"
}
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
println(buildTypes)
println(productFlavors)
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
println("SourceName:${sourceName}")
println("SourcePath:${sourcePath}")
println("testTaskName:${testTaskName}")
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
println("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
}
}
}
接受的答案有点过时了。这是我们刚刚实施的类似修复。在模块(即应用程序)中 build.gradle 添加:
apply plugin: 'jacoco'
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
这确实需要 JaCoCo 7.6+,但您可能已经在使用它了。
工作室注意事项:
- 这仅修复了 CLI。如果您使用 JaCoCo 从 Studio 运行 覆盖率,Robolectric 覆盖率仍未报告。默认的 IntelliJ Coverage Runner 似乎工作正常。
- 测试在 Studio 中间歇性崩溃,除非我将 -noverify 添加到 Android JUnit -> VM 选项
在 android 工作室中将报道 运行ner 更改为 jacoco
1- select 应用程序(项目的根目录)
2 单击菜单(运行 --> 编辑配置 --> 代码覆盖率 --> 选择 JaCoCo)。
这是一个老问题,但对于那些仍然面临问题的人来说,值得一提的是,如果您正在设置 JaCoCo + Robolectric + Espresso - 您确实会使用 includeNoLocationClasses
,但是 Java9+ 仍然会看到这个错误,并且可能会在这里结束。将以下代码片段添加到您的模块 build.gradle 文件
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
我想在我的 android 项目中为我的 JUnit 测试生成代码覆盖率报告,所以我添加了 JaCoCo gradle 插件。这是我的项目级别 build.gradle
文件:
apply plugin: 'jacoco'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-beta6'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
subprojects { prj ->
apply plugin: 'jacoco'
jacoco {
toolVersion '0.7.6.201602180812'
}
task jacocoReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
group = 'Reporting'
description = 'Generate Jacoco coverage reports after running tests.'
reports {
xml {
enabled = true
destination "${prj.buildDir}/reports/jacoco/jacoco.xml"
}
html {
enabled = true
destination "${prj.buildDir}/reports/jacoco"
}
}
classDirectories = fileTree(
dir: 'build/intermediates/classes/debug',
excludes: [
'**/R*.class',
'**/BuildConfig*',
'**/*$$*'
]
)
sourceDirectories = files('src/main/java')
executionData = files('build/jacoco/testDebugUnitTest.exec')
doFirst {
files('build/intermediates/classes/debug').getFiles().each { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
}
jacoco {
toolVersion '0.7.6.201602180812'
}
task jacocoFullReport(type: JacocoReport, group: 'Coverage reports') {
group = 'Reporting'
description = 'Generates an aggregate report from all subprojects'
//noinspection GrUnresolvedAccess
dependsOn(subprojects.jacocoReport)
additionalSourceDirs = project.files(subprojects.jacocoReport.sourceDirectories)
sourceDirectories = project.files(subprojects.jacocoReport.sourceDirectories)
classDirectories = project.files(subprojects.jacocoReport.classDirectories)
executionData = project.files(subprojects.jacocoReport.executionData)
reports {
xml {
enabled = true
destination "${buildDir}/reports/jacoco/full/jacoco.xml"
}
html {
enabled = true
destination "${buildDir}/reports/jacoco/full"
}
}
doFirst {
//noinspection GroovyAssignabilityCheck
executionData = files(executionData.findAll { it.exists() })
}
}
运行宁 ./gradlew jacocoFullReport
效果很好。但不幸的是,运行 和 RobolectricTestRunner
的测试未报告覆盖率(在测试中明显调用的指令未报告为已覆盖)。没有 @RunWith
注释或 运行 且 MockitoJUnitTestRunner
的测试报告覆盖率很好。
如能解决此问题,我们将不胜感激。
更新 1: 我注意到我应该使用 RobolectricGradleTestRunner
。但是没有用。
可能的解决方法是已知问题 - https://github.com/jacoco/jacoco/pull/288
或者将jacoco版本降级到0.7.1.201405082137
更新
不再需要解决方法。您必须使用 gradle 版本 2.13
和 jacoco 版本 0.7.6.201602180812
.
更新根 build.gradle
:
buildscript {
dependencies {
classpath 'org.jacoco:org.jacoco.core:0.7.6.201602180812'
}
}
task wrapper( type: Wrapper ) {
gradleVersion = '2.13'
}
运行 ./gradlew wrapper
更新项目build.gradle
:
apply plugin: 'jacoco'
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
我遇到了同样的问题,但现在按照此 link、
解决了我的问题问题link:https://github.com/robolectric/robolectric/issues/2230
这里提到了这个问题的解决方案:
我遇到了同样的问题。我更改了 jacoco 插件版本并添加了 includenolocationclasses 属性。这是工作 jacoco.gradle 文件(我正在使用 gradle 包装器 2.14.1):
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.6.201602180812"
}
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
println(buildTypes)
println(productFlavors)
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
println("SourceName:${sourceName}")
println("SourcePath:${sourcePath}")
println("testTaskName:${testTaskName}")
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
println("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
}
}
}
接受的答案有点过时了。这是我们刚刚实施的类似修复。在模块(即应用程序)中 build.gradle 添加:
apply plugin: 'jacoco'
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
这确实需要 JaCoCo 7.6+,但您可能已经在使用它了。
工作室注意事项:
- 这仅修复了 CLI。如果您使用 JaCoCo 从 Studio 运行 覆盖率,Robolectric 覆盖率仍未报告。默认的 IntelliJ Coverage Runner 似乎工作正常。
- 测试在 Studio 中间歇性崩溃,除非我将 -noverify 添加到 Android JUnit -> VM 选项
在 android 工作室中将报道 运行ner 更改为 jacoco 1- select 应用程序(项目的根目录) 2 单击菜单(运行 --> 编辑配置 --> 代码覆盖率 --> 选择 JaCoCo)。
这是一个老问题,但对于那些仍然面临问题的人来说,值得一提的是,如果您正在设置 JaCoCo + Robolectric + Espresso - 您确实会使用 includeNoLocationClasses
,但是 Java9+ 仍然会看到这个错误,并且可能会在这里结束。将以下代码片段添加到您的模块 build.gradle 文件
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}