android - JaCoCo no funciona con pruebas Robolectric
code-coverage (5)
Quería generar informes de cobertura de código en mis pruebas JUnit en mi proyecto de Android, así que agregué el plugin JaCoCo gradle. Este es mi archivo build.gradle
nivel de proyecto:
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() })
}
}
Funciona muy bien ejecutando ./gradlew jacocoFullReport
. Pero, desafortunadamente, no se informa la cobertura de las pruebas que se ejecutan con RobolectricTestRunner
(las instrucciones que obviamente se mencionan en las pruebas no se informan como cubiertas). Las pruebas sin la anotación @RunWith
o ejecutadas con MockitoJUnitTestRunner
informan que la cobertura está bien.
Cualquier ayuda sería apreciada para solucionar este problema.
Actualización 1: noté que debería estar usando RobolectricGradleTestRunner
. Pero no ayudó.
La respuesta aceptada es un poco anticuada. Aquí hay una solución similar que acabamos de implementar. En el módulo (es decir, la aplicación) build.gradle agregar:
apply plugin: ''jacoco''
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
Esto requiere JaCoCo 7.6+, pero es probable que ya lo estés usando.
Notas para el estudio:
- Esto solo corrige el CLI. Si ejecuta la cobertura de Studio utilizando JaCoCo, la cobertura de Robolectric aún no se informa. El IntelliJ Coverage Runner por defecto parece funcionar bien.
- La prueba se bloqueaba de forma intermitente en Studio a menos que agregue -noverificar a Android JUnit -> Opciones de VM
Me enfrentaba al mismo problema, pero ahora está resuelto por mí siguiendo este enlace,
enlace del problema: https://github.com/robolectric/robolectric/issues/2230
La solución para este problema se menciona aquí:
Se sabe que existe un problema con la posible solución alternativa: https://github.com/jacoco/jacoco/pull/288
O bajar la versión 0.7.1.201405082137
a 0.7.1.201405082137
ACTUALIZAR
La solución ya no es necesaria. Debe usar la versión gradle 2.13
y la versión 0.7.6.201602180812
.
Actualizar root build.gradle
:
buildscript {
dependencies {
classpath ''org.jacoco:org.jacoco.core:0.7.6.201602180812''
}
}
task wrapper( type: Wrapper ) {
gradleVersion = ''2.13''
}
Ejecutar ./gradlew wrapper
Actualizar proyecto build.gradle
:
apply plugin: ''jacoco''
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
Tuve el mismo problema. Cambié la versión del complemento jacoco y agregué la propiedad includeenolocationclasses. Aquí está el archivo jacoco.gradle en funcionamiento (estoy usando Gradle Wrap 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
}
}
}
}
}