Pregunta Cobertura del código de prueba de Android con el plugin JaCoCo Gradle


Soy nuevo en las pruebas de Gradle y Android, pero ya he convertido mi proyecto de Android para compilar con Gradle.

Ahora estoy intentando realizar una cobertura de prueba de un proyecto de Android con el complemento JaCoCo de Gradle.

He agregado lo siguiente a mi archivo build.gradle:

apply plugin: 'jacoco'

Y cuando ejecuto "gradle jacocoTestReport" aparece el siguiente error:

Task 'jacocoTestReport' not found in root project '<project name>'.

De la documentación se supone que también debo aplicar el plugin 'java', pero entra en conflicto con el plugin 'android'.

¿Hay alguna forma de evitar esto?

Gracias por adelantado.


32
2017-08-21 13:06


origen


Respuestas:


Así es como estoy usando Jacoco:

buildscript {
  repositories {
    mavenLocal()
    mavenCentral()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:0.12.+'
    classpath 'org.robolectric:robolectric-gradle-plugin:0.11.+'
  }
}

apply plugin: 'com.android.application'
apply plugin: 'robolectric'
apply plugin: 'jacoco'

android {
  compileSdkVersion 20
  buildToolsVersion "20.0.0"

  defaultConfig {
    applicationId "YOUR_PACKAGE_NAME"
    minSdkVersion 10
    targetSdkVersion 20
    testHandleProfiling true
    testFunctionalTest true
  }
  buildTypes {
    debug {
      testCoverageEnabled false
    }
    release {
      runProguard false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
    }
  }
  jacoco {
    version "0.7.1.201405082137"
  }
  packagingOptions {
    exclude 'META-INF/DEPENDENCIES.txt'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/dependencies.txt'
    exclude 'META-INF/LGPL2.1'
    exclude 'META-INF/services/javax.annotation.processing.Processor'
    exclude 'LICENSE.txt'
  }
}

robolectric {
  include '**/*Test.class'
  exclude '**/espresso/**/*.class'

  maxHeapSize "2048m"
}

jacoco {
  toolVersion "0.7.1.201405082137"
}

// Define coverage source.
// If you have rs/aidl etc... add them here.
def coverageSourceDirs = [
    'src/main/java',
]

task jacocoTestReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest") {
  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('$$', '$'))
      }
    }
  }
}


dependencies {
  androidTestCompile('junit:junit:4.11') {
    exclude module: 'hamcrest-core'
  }
  androidTestCompile('org.robolectric:robolectric:2.3') {
    exclude module: 'classworlds'
    exclude module: 'maven-artifact'
    exclude module: 'maven-artifact-manager'
    exclude module: 'maven-error-diagnostics'
    exclude module: 'maven-model'
    exclude module: 'maven-plugin-registry'
    exclude module: 'maven-profile'
    exclude module: 'maven-project'
    exclude module: 'maven-settings'
    exclude module: 'nekohtml'
    exclude module: 'plexus-container-default'
    exclude module: 'plexus-interpolation'
    exclude module: 'plexus-utils'
    exclude module: 'wagon-file'
    exclude module: 'wagon-http-lightweight'
    exclude module: 'wagon-http-shared'
    exclude module: 'wagon-provider-api'
    exclude group: 'com.android.support', module: 'support-v4'
  }
}

El código anterior también contiene una solución para https://code.google.com/p/android/issues/detail?id=69174.

Más detalles: http://chrisjenx.com/gradle-robolectric-jacoco-dagger/


23
2018-06-15 15:36



Estoy usando JaCoCo con un proyecto que usa RoboGuice, Butterknife y Robolectric. Pude configurarlo utilizando la solución de @Hieu Rocker, sin embargo, hubo algunos inconvenientes menores, es decir, en nuestro proyecto usamos sabores y tenemos algunas pruebas adicionales para esos sabores, así como código extra de Java para cada uno de ellos. También utilizamos diferentes tipos de compilación. Por lo tanto, una solución para confiar en la tarea "testDebug" no era lo suficientemente buena. Aquí está mi solución: En build.gradle en aplicación módulo agregar

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

Entonces crea un jacoco.gradle archivo dentro de aplicación módulo con el siguiente contenido:


    aplicar el complemento: 'jacoco'

    jacoco {
        toolVersion "0.7.1.201405082137"
    }

    def getFlavorFromVariant (String variantName) {
        def flavorString = variantName.replaceAll (/ (. *) ([A-Z]. *) /) {all, flavorName, buildTypeName ->
           flavorName
        }
        devolver flavorString;
    }

    def getBuildTypeFromVariant (String variantName) {
        def buildTypeString = variantName.replaceAll (/ (. *) ([A-Z]. *) /) {all, flavorName, buildTypeName ->
            "$ {buildTypeName.toLowerCase ()}"
        }
        devuelve buildTypeString;
    }

    def getFullTestTaskName (String variantName) {
        return "test $ {variantName.capitalize ()} UnitTest";
    }

    android.applicationVariants.all {variant ->
        def variantName = variant.name;
        def flavorFromVariant = getFlavorFromVariant ("$ {variantName}");
        def buildTypeFromVariant = getBuildTypeFromVariant ("$ {variantName}");
        def testTaskName = getFullTestTaskName ("$ {variantName}")

        task ("jacoco $ {variantName.capitalize ()} TestReport", escriba: JacocoReport, dependsOn: testTaskName) {
            group = "Informes"
            description = "Generar informes de cobertura de JaCoCo después de ejecutar pruebas para la variante: $ {variantName}."
            informes {
                xml.enabled = true
                html.enabled = true
            }

            classDirectories = fileTree (
                    dir: "./build/intermediates/classes/${flavorFromVariant}/${buildTypeFromVariant}",
                    excluye: ['** / R * .class',
                               '** / * $ InjectAdapter.class',
                               '** / * $ ModuleAdapter.class',
                               '** / * $ ViewInjector * .class'
                    ]
            )

            logger.info ("Configuración de JaCoCo para sabor: $ {flavorFromVariant}, buildType: $ {buildTypeFromVariant}, task: $ {testTaskName}");

            def coverageSourceDirs = [
                    '../app/src/main/java',
                    "../app/src/${flavorFromVariant}/java"
            ]
            sourceDirectories = archivos (coverageSourceDirs)
            executionData = files ("$ dirDir / jacoco / $ {testTaskName} .exec")
            // Bit hacky pero corrige https://code.google.com/p/android/issues/detail?id=69174.
            // iteramos a través del árbol compilado .class y cambiamos el nombre de $$ a $.
            hacer primero {
                nuevo archivo ("$ buildDir / intermedios / clases /"). eachFileRecurse {archivo ->
                    if (file.name.contains ('$$')) {
                        file.renameTo (file.path.replace ('$$', '$'))
                    }
                }
            }
        }
    }

Puede ejecutarlo desde línea de comandos de esta manera:

.gradlew jacocoFlavor1DebugTestReport

o

.gradlew jacocoOtherflavorPrereleaseTestReport

En nuestro proyecto utilizamos una convención para no usar letras mayúsculas dentro de los nombres de tipo de compilación y sabor, pero si su proyecto no sigue esta convención, simplemente puede cambiar getFlavorFromVariant (..) y getBuildTypeFromVariant (..) funciones

Espero que esto ayude a alguien


6
2018-06-16 10:05



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

Hay un poco más en la respuesta aquí https://stackoverflow.com/a/32572259/1711454.


0
2017-09-14 19:22



¿Intentó agregar lo siguiente?

jacocoTestReport {
   group = "Reporting"
   description = "Generate Jacoco coverage reports after running tests."
   additionalSourceDirs = files(sourceSets.main.allJava.srcDirs)
}

Y luego, en lugar de correr ./gradlew jacocoTestReport correr ./gradlew test jacocoTestReport.

Si todo va bien, debería encontrar los resultados de la prueba en build/reports/jacoco/test/html/index.html.


-3
2017-12-11 16:40