J'ai récemment commencé à intégrer Android-gradle-plugin
1.1.0 dans l'un de mes projets. Le projet utilise robolectric 2.4
pour 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 ca:
--> 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-example project.
J'ai essayé d'intégrer JaCoCo pour générer des rapports pour les tests unitaires, mais il me semble qu'il n'exécute que androidTests
qui sont essentiellement des tests d'instrumentation.
Après quelques recherches sur Google, je suis tombé sur quelques projets sur GitHub et d'autres articles, mais ils se concentrent principalement sur les versions précédentes de Android-gradle-plugin
ou utilisez d'autres plugins tiers comme Android-unit-test
par exemple ici .
Peut-être que j'ai perdu ma capacité de google. Mais quelqu'un peut-il m'orienter dans une direction où je peux trouver des documentations concernant les nouveaux trucs dans Android plugin gradle et comment exécuter la tâche jacoco uniquement pour les tests unitaires?
[~ # ~] mise à jour [~ # ~]
Adopté le script 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 cela, le ./gradlew jacocoReport
exécute et génère le rapport, mais il affiche une couverture de test de 0 (zéro), ce qui est impossible car au moins la moitié de toutes les classes sont testées.
UPDATE_2
J'ai essayé ceci exemple . Ajout de la tâche suivante à l'un de mes fichiers de construction 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 nulle.
UPDATE_3
Il semble que la tâche de UPDATE_2 a fonctionné mais uniquement pour le module avec apply plugin: 'com.Android.application'
(Les rapports sont générés correctement). Mais pour les modules qui sont Android bibliothèques (apply plugin: 'com.Android.library'
) les rapports montrent une couverture nulle, bien que les modules contiennent plus de tests que le module d'application.
UPDATE_4
J'ai créé un exemple de projet simple qui illustre mon problème. Actuellement, si vous exécutez ./gradlew jacocoReport
le rapport est généré, mais aucune couverture de test n'est affichée pour les projets de module. Voir ceci lien
Note courte: Quand les tests étaient AndroidUnitTests (whiteout JUnit 4 et Robolectric), les rapports JaCoCo montraient la couverture pour tous les modules.
Des idées?
Après les tracas, j'ai décidé de créer un plugin Gradle open source pour cela.
Racine 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'
Ensuite, exécutez simplement
./gradlew jacocoTestReportDebug
Il exécutera les tests JUnit en mode débogage, puis vous donnera la sortie Jacoco au format xml et html dans le répertoire de construction correspondant.
Il prend également en charge les saveurs. Ayant 2 saveurs rouge et bleu, ces tâches seraient créées
Après quelques recherches supplémentaires, je suis tombé sur cela projet J'ai dû apporter quelques modifications pour que la solution puisse fonctionner pour mon type de projet, mais maintenant les rapports de couverture des tests sont générés correctement.
J'ai poussé les changements adoptés dans mon exemple github repo au cas où quelqu'un aurait un problème similaire à l'avenir.
J'ai configuré mes tests unitaires pour le grade 1.2 en utilisant ceci article de blog . Ensuite, j'ai rassemblé les informations que j'ai trouvées ici et ailleurs pour ajouter une couverture de code à des modules indépendants au lieu de l'ensemble du projet. Dans mon module de bibliothèque build.gradle
fichier, j'ai ajouté ce qui suit:
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
fichier, j'ai ajouté des exclusions courantes:
ext.jacocoExcludes = [
'Android/**',
'**/*$$*',
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Service.*'
]
En outre, il semble que la couverture de code pour les tests unitaires puisse être intégrée à l'avenir problème 144664
J'ai enfin pu voir ma couverture de code 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('$$', '$'))
}
}
}
}
puis dans le fichier build.gradle du module (je le mets entre Android
et dependencies
):
apply from: '../jacoco.gradle'
Toujours dans le bloc defaultConfig
de Android
. J'ai ajouté ceci (je ne sais pas si c'est nécessaire, mais je l'ai obtenu de ce blog ):
Android {
defaultConfig {
testHandleProfiling true
testFunctionalTest true
}
}
Prendre plaisir.
Attention: c'est un hack! En utilisant votre configuration ci-dessus, j'ai mis en place un hack pour basculer le Android entre l'application et la bibliothèque en fonction des tâches de construction choisies. Cela fonctionne bien pour moi car je ne finis pas par valider du 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 d'outils Android tools corrige cela bientôt.
Vous pouvez essayer d'utiliser ce plugin Gradle: https://github.com/arturdm/jacoco-Android-gradle-plugin
Fondamentalement, 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'
Par conséquent, vous devriez obtenir une tâche JacocoReport
pour chaque variante. Exécutez la commande ci-dessous pour générer des rapports de couverture de code pour chacun d'eux.
$ ./gradlew jacocoTestReport
J'étais confronté exactement au même problème que vous. Aujourd'hui, j'ai complètement supprimé Android studio, Android sdk, gradle. Ensuite, réinstallez tout. Après cela, je viens d'ajouter à l'intérieur de l'application build.gradle.
debug {testCoverageEnabled true} Ensuite, je lance ./gradlew connectedChec. Tout fonctionne parfaitement. Android studio par défaut Jacoco fonctionne bien pour moi. Je pense qu'il est également possible de créer une tâche jacocoTestReport puis de créer une couverture de code.Je ne sais pas pourquoi gradle et Android le studio ne fonctionnait pas auparavant.
Je résous les problèmes avec JaCoCo et le fais fonctionner avec le dernier gradle Android plugin 1.1.3
Projet avec les derniers scripts de gradle: https://github.com/OleksandrKucherenko/meter
Les références:
Comment attacher sa propre implémentation au lieu de Mocks dans Android Tests unitaires studio? https: // plus .google.com/117981280628062796190/posts/8jWV22mnqUB
Petit indice pour tous ceux qui essaient d'utiliser la couverture JaCoCo dans Android builds ... conclusion inattendue !!! - https://plus.google.com/117981280628062796190/posts/RreU44qmeuP
Rapport JaCoCo XML/HTML pour les tests unitaires https://plus.google.com/u/0/+OleksandrKucherenko/posts/6vNWkkLed3b
Veuillez créer un exemple et je pourrai y jeter un œil. Je suppose que c'est une configuration de chemin manquante.
voici deux exemples à quoi cela pourrait ressembler