android unit-testing android-gradle jacoco

Cobertura de código de pruebas conjuntas y de Jacoco con android-gradle-plugin>=1.1



unit-testing (9)

Recientemente comencé a integrar android-gradle-plugin 1.1.0 en uno de mis proyectos. El proyecto usa robolectric 2.4 para ejecutar pruebas unitarias.

Es un proyecto de varios módulos con dependencias muy complejas (algunos módulos dependen de otros módulos). Algo como eso:

--> application-module (dependsOn: module1, module2, module-core) --> module1 (dependsOn: module-core) --> module2 (dependsOn: module-core) --> module-core (dependsOn: module3, module4) --> module3 (library dependencies) --> module4 (library dependencies)

Para obtener una imagen más jacoco-example consulte el proyecto jacoco-example .

Traté de integrar JaCoCo para generar informes para las pruebas unitarias, pero me parece que solo ejecuta androidTests que son básicamente pruebas de instrumentación.

Después de googlearme, me encontré con algunos proyectos en GitHub y otros artículos, pero principalmente se centran en versiones anteriores del android-gradle-plugin o están usando otros complementos de terceros, como android-unit-test de la android-unit-test por ejemplo, aquí. .

Puede ser que haya perdido mi capacidad de googlear. Pero, ¿puede alguien señalarme una dirección en la que pueda encontrar documentación sobre lo nuevo en Android gradle plugin y cómo ejecutar la tarea de jacoco solo para pruebas unitarias?

ACTUALIZAR

Adoptó el script del ejemplo de nenick :

apply plugin: "jacoco" configurations { jacocoReport } task jacocoReport(dependsOn: ''testDebug'') << { ant { taskdef(name:''jacocoreport'', classname: ''org.jacoco.ant.ReportTask'', classpath: configurations.jacocoReport.asPath) mkdir dir: "${buildDir}/test-coverage-report" mkdir dir: "${buildDir}/reports/jacoco/test/" jacocoreport { executiondata = files("${buildDir}/jacoco/testDebug.exec") structure(name: "${rootProject.name}") { classfiles { fileset (dir: "${buildDir}/intermediates/classes/debug") { //exclude(name: ''**/*_*.class'') exclude(name: ''**/R.class'') exclude(name: ''**/R$*.class'') exclude(name: ''**/BuildConfig.class'') } } sourcefiles { fileset dir: "src/main/java" fileset dir: "${buildDir}/generated/source/buildConfig/debug" fileset dir: "${buildDir}/generated/source/r/debug" } } xml destfile: "${buildDir}/reports/jacoco/test/jacocoTestReport.xml" html destdir: "${buildDir}/test-coverage-report/" } } } dependencies { jacocoReport ''org.jacoco:org.jacoco.ant:0.7.2.201409121644'' }

Después de eso, el ./gradlew jacocoReport ejecuta y genera el informe, pero muestra una cobertura de prueba de 0 (cero), lo cual es imposible porque al menos la mitad de todas las clases se prueban.

UPDATE_2

Trató este example . Agregar la siguiente tarea a uno de mis archivos de compilación gradle:

task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") { group = "Reporting" description = "Generate Jacoco coverage reports" classDirectories = fileTree( dir: "${buildDir}/intermediates/classes/debug", excludes: [''**/R.class'', ''**/R$*.class'', ''**/*$ViewInjector*.*'', ''**/BuildConfig.*'', ''**/Manifest*.*''] ) sourceDirectories = files("${buildDir.parent}/src/main/java") additionalSourceDirs = files([ "${buildDir}/generated/source/buildConfig/debug", "${buildDir}/generated/source/r/debug" ]) executionData = files("${buildDir}/jacoco/testDebug.exec") reports { xml.enabled = true html.enabled = true } }

El mismo problema, los informes se generan, pero la cobertura del código sigue siendo cero.

UPDATE_3

Parece que la tarea de UPDATE_2 funcionó, pero solo para el módulo con el apply plugin: ''com.android.application'' (Los informes a se generaron correctamente). Pero para los módulos que son bibliotecas de Android ( apply plugin: ''com.android.library'' ), los informes muestran cobertura cero, aunque los módulos contienen más pruebas que el módulo de la aplicación.

UPDATE_4

Creé un proyecto de ejemplo simple que demuestra mi problema. Actualmente, si ejecuta ./gradlew jacocoReport , se genera el informe, pero no se muestra ninguna cobertura de prueba para los proyectos del módulo. Ver este jacoco-example

Nota breve: cuando las pruebas fueron AndroidUnitTests (whiteout JUnit 4 y Robolectric) los informes de JaCoCo mostraron cobertura para todos los módulos.

¿Algunas ideas?


Advertencia: ¡Esto es un truco! Usando su configuración anterior, armé un truco para cambiar el plugin de Android entre la aplicación y la biblioteca, dependiendo de las tareas de compilación elegidas. Esto funciona bien para mí porque no termino cometiendo código con el modo de aplicación configurado.

// dynamically change the android plugin to application if we are running unit tests or test reports. project.ext.androidPlugin = ''com.android.library'' for (String taskName : project.gradle.startParameter.taskNames) { if (taskName.contains(''UnitTest'') || taskName.contains(''jacocoTestReport'')) { project.ext.androidPlugin = ''com.android.application'' break } } logger.lifecycle("Setting android pluging to ${project.ext.androidPlugin}") apply plugin: project.ext.androidPlugin ... apply plugin: ''jacoco'' configurations { jacocoReport } task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") { group = "Reporting" description = "Generate Jacoco coverage reports" classDirectories = fileTree( dir: "${buildDir}/intermediates/classes/debug", excludes: [''**/R.class'', ''**/R$*.class'', ''**/*$ViewInjector*.*'', ''**/BuildConfig.*'', ''**/Manifest*.*''] ) sourceDirectories = files("${buildDir.parent}/src/main/java") additionalSourceDirs = files([ "${buildDir}/generated/source/buildConfig/debug", "${buildDir}/generated/source/r/debug" ]) executionData = files("${buildDir}/jacoco/testDebug.exec") reports { xml.enabled = true html.enabled = true } }

Esperemos que el equipo de herramientas de Android corrija esto pronto.


Configuré mis pruebas de unidad para Gradle 1.2 usando esta publicación de blog . Luego reconstruí la información que encontré aquí y en otros lugares para agregar cobertura de código a módulos independientes en lugar de todo el proyecto. En mi archivo de biblioteca build.gradle , agregué lo siguiente:

apply plugin: ''jacoco'' def jacocoExcludes = [ ''com/mylibrary/excludedpackage/**'' ] android { ... } android.libraryVariants.all { variant -> task("test${variant.name.capitalize()}WithCoverage", type: JacocoReport, dependsOn: "test${variant.name.capitalize()}") { group = ''verification'' description = "Run unit test for the ${variant.name} build with Jacoco code coverage reports." classDirectories = fileTree( dir: variant.javaCompile.destinationDir, excludes: rootProject.ext.jacocoExcludes.plus(jacocoExcludes) ) sourceDirectories = files(variant.javaCompile.source) executionData = files("${buildDir}/jacoco/test${variant.name.capitalize()}.exec") reports { xml.enabled true xml.destination "${buildDir}/reports/jacoco/${variant.name}/${variant.name}.xml" html.destination "${buildDir}/reports/jacoco/${variant.name}/html" } } }

Y en mi proyecto build.gradle , build.gradle comunes:

ext.jacocoExcludes = [ ''android/**'', ''**/*$$*'', ''**/R.class'', ''**/R$*.class'', ''**/BuildConfig.*'', ''**/Manifest*.*'', ''**/*Service.*'' ]

Además, parece que la cobertura del código para pruebas unitarias puede estar incorporada en el futuro. code.google.com/p/android/issues/detail?id=144664


Después de buscar un poco más en este project , tuve que hacer algunas modificaciones para que la solución pueda funcionar para mi tipo de proyecto, pero ahora los informes de cobertura de prueba se generan correctamente.

He introducido los cambios adoptados en mi jacoco-example en caso de que alguien tenga un problema similar en el futuro.


Después de la molestia, decidí crear un plugin Gradle de código abierto para eso.

Root build.gradle

buildscript { repositories { mavenCentral() // optional if you have this one already } dependencies { classpath ''com.vanniktech:gradle-android-junit-jacoco-plugin:0.8.0'' } } apply plugin: ''com.vanniktech.android.junit.jacoco''

Entonces simplemente ejecuta

./gradlew jacocoTestReportDebug

Ejecutará las pruebas de JUnit en modo de depuración y luego le dará la salida de Jacoco en formato xml y html en el directorio de compilación correspondiente.

También es compatible con sabores. Tener 2 sabores rojo y azul esas tareas se crearían

  • jacocoTestReportRedDebug
  • jacocoTestReportBlueDebug
  • jacocoTestReportRedRelease
  • jacocoTestReportBlueRelease

Estaba enfrentando exactamente el mismo problema que tú. Hoy hice completamente eliminado el estudio de android, android sdk, gradle. Luego vuelve a instalar todo. Después de eso, acabo de agregar dentro de la aplicación build.gradle.

debug {testCoverageEnabled true} Luego ejecuto ./gradlew connectedChec. Todo funciona a la perfección. Android studio por defecto Jacoco funciona bien para mí. Creo que también es posible crear una tarea jacocoTestReport y luego crear una cobertura de código. No sé por qué gradle y android studio no funcionaban anteriormente.


Finalmente pude ver la cobertura de mi código de las pruebas JUnit con Android Studio 1.1.

jacoco.gradle

apply plugin: ''jacoco'' jacoco { toolVersion "0.7.1.201405082137" } def coverageSourceDirs = [ "$projectDir/src/main/java", ] task jacocoTestReport(type: JacocoReport, dependsOn: "testDebug") { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." reports { xml.enabled = true html.enabled = true } classDirectories = fileTree( dir: ''./build/intermediates/classes/debug'', excludes: [''**/R*.class'', ''**/*$InjectAdapter.class'', ''**/*$ModuleAdapter.class'', ''**/*$ViewInjector*.class'' ] ) sourceDirectories = files(coverageSourceDirs) executionData = files("$buildDir/jacoco/testDebug.exec") // Bit hacky but fixes https://code.google.com/p/android/issues/detail?id=69174. // We iterate through the compiled .class tree and rename $$ to $. doFirst { new File("$buildDir/intermediates/classes/").eachFileRecurse { file -> if (file.name.contains(''$$'')) { file.renameTo(file.path.replace(''$$'', ''$'')) } } } }

y luego dentro del archivo build.gradle del módulo (lo puse entre android y dependencies ):

apply from: ''../jacoco.gradle''

También en el bloque defaultConfig de android . He agregado esto (no sé si es necesario, pero lo tengo de este blog ):

android { defaultConfig { testHandleProfiling true testFunctionalTest true } }

Disfrutar.


Por favor crea un ejemplo y puedo echarle un vistazo. Supongo que es una configuración de ruta faltante.

  • incluir todos los archivos de cobertura (* .exec)
  • agregue todas las rutas de origen (module / src / main / java)
  • agregar todas las rutas de clase (module / build / intermedios / classes / debug)

aquí dos ejemplos de cómo podría verse


Puede intentar usar este plugin de Gradle: https://github.com/arturdm/jacoco-android-gradle-plugin

Básicamente, todo lo que necesita hacer es aplicarlo así:

buildscript { repositories { jcenter() } dependencies { classpath ''com.dicedmelon.gradle:jacoco-android:0.1.1'' } } apply plugin: ''com.android.library'' // or ''com.android.application'' apply plugin: ''jacoco-android''

Como resultado, debería obtener una tarea de JacocoReport para cada variante. Ejecute el siguiente comando para generar informes de cobertura de código para todos ellos.

$ ./gradlew jacocoTestReport


Resuelvo problemas con JaCoCo y lo hago funcionar con el último plugin android de gradle 1.1.3

Proyecto con los últimos scripts de Gradle: https://github.com/OleksandrKucherenko/meter

Referencias

¿Cómo adjuntar una implementación propia en lugar de Mocks en las pruebas de Android Studio Unit? https://plus.google.com/117981280628062796190/posts/8jWV22mnqUB

Una pequeña pista para todos los que intenten usar la cobertura de JaCoCo en las compilaciones de Android ... ¡hallazgo inesperado! https://plus.google.com/117981280628062796190/posts/RreU44qmeuP

Informe XML / HTML de JaCoCo para pruebas unitarias https://plus.google.com/u/0/+OleksandrKucherenko/posts/6vNWkkLed3b