Jacoco et Unit testent la couverture du Code avec android-gradle-plugin> = 1.1

j'ai récemment commencé à intégrer android-gradle-plugin 1.1.0 dans un de mes projets. Le projet utilise robolectric 2.4 exécuter des tests unitaires.

c'est un projet multi-modules avec des dépendances très complexes (certains modules dépendent d'autres modules). Quelque chose comme ça:

--> 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)

pour une image plus claire veuillez voir jacoco-exemple projet.

j'ai essayé d'intégrer JaCoCo pour générer des rapports pour les tests unitaires, mais il me semble qu'il ne fonctionne que <!--5 qui sont essentiellement des essais d'instrumentation.

après un peu de google, j'ai rencontré quelques projets sur GitHub et d'autres articles, mais ils sont principalement axés sur les versions précédentes du android-gradle-plugin ou utilisez d'autres plugins tiers comme android-unit-testpar exemple ici.

Peut être que j'ai perdu ma capacité à google. Mais quelqu'un peut m'indiquer une direction où je peux trouver quelques documentations concernant les nouveaux trucs dans le plugin Gradle android et comment exécuter la tâche jacoco uniquement pour les tests unitaires?

UPDATE

a Adopté le script à partir de exemple 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'
}

Après le ./gradlew jacocoReport exécute et génère le rapport, mais il affiche 0 (zéro) couverture de test, ce qui est impossible car au moins la moitié de toutes les classes sont testées.

UPDATE_2

Essayé cette exemple. Ajouter la tâche suivante à un de mes fichiers de build 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
    }
}

même problème, les rapports sont générés, mais la couverture du code est toujours zéro.

UPDATE_3

il se connecte que la tâche de UPDATE_2 a fonctionné mais seulement pour le module avec apply plugin: 'com.android.application' (Les rapports générés correctement). Mais pour les modules qui sont des bibliothèques android (apply plugin: 'com.android.library') les rapports montrent une couverture nulle, bien que les modules contiennent plus de tests que l'application module.

UPDATE_4

J'ai créé un projet d'exemple simple qui démontre mon problème. Actuellement si vous courez ./gradlew jacocoReport le rapport est généré, mais aucune couverture d'essai n'est affichée pour les projets du module. Voir cette lien

brève note: lorsque les tests étaient des AndroidUnitTests (whiteout JUnit 4 et Robolectric) les rapports de JaCoCo montraient une couverture pour tous les modules.

des idées?

35
demandé sur neillb 2015-02-18 18:10:12

9 réponses

après les tracas j'ai décidé de créer un open source Gradle plugin pour que.

Racine de construire.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'

alors exécutez simplement

./gradlew jacocoTestReportDebug

il exécutera les tests de JUnit en mode Debug puis vous donnera la sortie Jacoco en format xml et html dans le répertoire de compilation correspondant.

il supporte aussi les saveurs. Avoir 2 saveurs rouge et bleu ces tâches serait créé

  • jacocoTestReportRedDebug
  • jacocoTestReportBlueDebug
  • jacocoTestReportRedRelease
  • jacocoTestReportBlueRelease
14
répondu Niklas 2017-08-20 11:25:10

Après quelques recherche supplémentaires, je suis tombé sur ce projet J'ai dû faire quelques modifications pour que la solution puisse fonctionner pour mon type de projet, mais maintenant les rapports de couverture d'essai sont générés correctement.

j'ai poussé les changements adoptés à mon exemple dépôt github dans le cas où quelqu'un va avoir un problème similaire dans l'avenir.

8
répondu Serj Lotutovici 2015-04-13 14:09:59

j'ai configuré mes tests unitaires pour gradle 1.2 en utilisant ceci blog. Puis j'ai rassemblé des informations que j'ai trouvées ici et ailleurs pour ajouter de la couverture de code à des modules indépendants au lieu de l'ensemble du projet. Dans mon module de bibliothèque build.gradle le fichier, j'ai ajouté le code suivant:

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"
        }
    }
}

Et dans mon projet build.gradle le fichier, j'ai ajouté de la commune exclut:

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

en outre, il semble que la couverture du code pour les tests unitaires pourrait être intégrée dans le futur Problème 144664

3
répondu Chris Feist 2015-10-29 01:17:16

attention: Ceci est un hack! En utilisant votre configuration ci-dessus, j'ai mis en place un hack pour basculer le plugin android Entre application et bibliothèque en fonction des tâches de construction choisies. Cela fonctionne bien pour moi parce que je ne finis pas par commettre le code avec le mode d'application défini.

// 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
    }
}

espérons que l'équipe des outils android corrigera cela bientôt.

2
répondu vangorra 2015-02-21 17:13:22

j'ai enfin pu voir mon code de couverture des tests JUnit avec 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('$$', '$'))
            }
        }
    }
}

et puis dans la construction.gradle fichier du module (je l'ai mis entre android et dependencies):

apply from: '../jacoco.gradle'

dans le defaultConfig bloc android. J'ai ajouté ceci (Je ne sais pas si c'est nécessaire, mais j'ai obtenu cela de ce blog):

android {
    defaultConfig {
        testHandleProfiling true
        testFunctionalTest true
    }
}

Profiter.

2
répondu Niklas 2015-03-18 13:55:36

Je résous les problèmes avec JaCoCo et le faire fonctionner avec le dernier plugin Gradle android 1.1.3

Projet avec la dernière gradle scripts: https://github.com/OleksandrKucherenko/meter

Références:

comment joindre sa propre implémentation au lieu de se moquer dans les tests D'Unité Android Studio? https://plus.google.com/117981280628062796190/posts/8jWV22mnqUB

petit conseil pour tous ceux qui essaient D'utiliser la couverture JaCoCo dans android construit... découverte inattendue!!! https://plus.google.com/117981280628062796190/posts/RreU44qmeuP

JaCoCo XML / HTML Report for Unit Testshttps://plus.google.com/u/0/+OleksandrKucherenko / posts/6vNWkkLed3b

1
répondu Oleksandr Kucherenko 2015-03-10 22:25:12

je faisais face exactement au même problème que vous. Aujourd'hui, j'ai complètement supprimé android studio, android sdk, gradle. Puis tout réinstaller. Après cela, j'ai juste ajouté à l'intérieur de la construction de l'application.gradle.

debug { testCoverageEnabled true } Puis-je exécuter ./ gradlew connectedChec. Tout fonctionne à la perfection. Studio Android par défaut Jacoco fonctionne très bien pour moi. Je pense qu'il est également possible de créer une tâche jacocoTestReport et ensuite de créer une couverture de code.Je ne sais pas pourquoi gradle et android studio ne fonctionnait pas auparavant.

1
répondu user1365169 2015-03-19 19:49:01

Vous pouvez essayer d'utiliser ce plugin Gradle: https://github.com/arturdm/jacoco-android-gradle-plugin

en gros, tout ce que vous devez faire est de l'appliquer comme ceci:

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'

en conséquence, vous devriez obtenir un JacocoReport tâche pour chaque variante. Exécutez la commande ci-dessous pour générer des rapports de couverture de code pour tous.

$ ./gradlew jacocoTestReport
1
répondu Artur Stepniewski 2015-11-30 19:59:42

veuillez créer un exemple et je peux jeter un coup d'oeil. Je suppose que c'est une configuration de chemin manquante.

  • inclure tous les fichiers (*.exec)
  • ajouter tous vos chemins de sources (module/src/main/java)
  • ajouter tous les chemins d'accès (module/build/intermédiaires/classes/debug)

voici deux exemples de ce que cela pourrait être

0
répondu nenick 2015-02-26 09:18:20