wake-up-neo.com

Android Testcodeabdeckung mit JaCoCo Gradle Plugin

Ich bin neu in Gradle und Android-Tests, aber ich habe mein Android-Projekt bereits in Gradle konvertiert.

Jetzt versuche ich, eine Testabdeckung eines Android-Projekts mit dem JaCoCo-Plugin von Gradle durchzuführen.

Ich habe meiner build.gradle-Datei folgendes hinzugefügt:

apply plugin: 'jacoco'

Und wenn ich "gradle jacocoTestReport" starte, wird folgender Fehler angezeigt:

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

Aus der Dokumentation soll ich auch das Plugin 'Java' anwenden, das jedoch mit dem Plugin 'Android' in Konflikt steht.

Gibt es da einen Weg?

Danke im Voraus.

32
Henrique Rocha

So verwende ich 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'
  }
}

Der obige Code enthält auch eine Problemumgehung für https://code.google.com/p/Android/issues/detail?id=69174 .

Weitere Details: http://chrisjenx.com/gradle-robolectric-jacoco-dagger/

23
Hieu Rocker

Ich verwende JaCoCo mit einem Projekt, das RoboGuice, Butterknife und Robolectric verwendet. Ich konnte es mit der @Hieu Rocker-Lösung einrichten, es gab jedoch einige kleinere Nachteile, d. H. In unserem Projekt verwenden wir Geschmacksrichtungen und einige zusätzliche Tests für diese Geschmacksrichtungen sowie zusätzlichen Java-Code für jeden von ihnen. Wir verwenden auch verschiedene Build-Typen. Daher war eine Lösung, die sich auf die Task "testDebug" stützte, nicht gut genug Hier ist meine Lösung: In build.gradle im app -Modul hinzufügen

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

Erstellen Sie anschließend eine jacoco.gradle -Datei im Modul app mit folgendem Inhalt:

 Plugin anwenden: 'jacoco' 

 jacoco {
 toolVersion "0.7.1.201405082137" 
 } 

 def getFlavorFromVariant (String variantName) {
 def flavorString = variantName.replaceAll (/ (. *) ([A-Z]. *) /) {alle, FlavorName, BuildTypeName -> 
 FlavorName 
 } 
 return Flavorstring; 
 } 

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

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

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

 task ("jacoco $ {variantName.capitalize ()} TestReport", Typ: JacocoReport, hängt vonOn: testTaskName) {
 group = "Berichterstellung" 
 description = "Generieren Sie JaCoCo-Abdeckungsberichte nach dem Ausführen von Tests für die Variante: $ {variantName}." 
 Berichte {
 xml.enabled = true 
 html.enabled = true 
 } 

 classDirectories = fileTree (
 dir: "./build/intermediates/classes/${flavorFromVariant}/${buildTypeFromVariant}",
 schließt aus: ['**/R * .class', 
 '* */* $ InjectAdapter.class ', 
' **/* $ ModuleAdapter.class ', 
' **/* $ ViewInjector * .class '
] 
) 
) 
 . logger.info ("JaCoCo für Flavor konfigurieren: $ {flavorFromVariant}, buildType: $ {buildTypeFromVariant}, Aufgabe: $ {testTaskName}");) ______. def coverageSourceDirs = [
 "../app/src/main/Java" ,
 "../app/src/${flavorFromVariant}/Java"
 ] 
 sourceDirectories = Dateien (coverageSourceDirs) 
 executionData = Dateien ("$ buildDir/jacoco/$ {testTaskName} .exec") 
 // Bit hacky, behebt aber https://code.google.com/p/Android/issues/detail?id=69174.
 // Wir durchlaufen die kompilierte .class-Struktur und benennen $$ in $ ..__ um. doFirst {
 neue Datei ("$ buildDir/intermediates/classes /"). eachFileRecurse {file -> 
 if (file.name.contains ('$$')) {
 file.renameTo (file.path.replace ('$$', '$')) 
 } 
 } 
 } 
 } 
 } 

Sie können es von der Kommandozeile aus so ausführen:

.gradlew jacocoFlavor1DebugTestReport

oder

.gradlew jacocoOtherflavorPrereleaseTestReport

In unserem Projekt verwenden wir eine Konvention, um keine Großbuchstaben innerhalb von Flavour- und Build-Typnamen zu verwenden. Wenn Ihr Projekt dieser Konvention jedoch nicht folgt, können Sie einfach getFlavorFromVariant (..) und getBuildTypeFromVariant (..) ändern. Funktionen

Hoffe das hilft jemandem

6
Piotr Zawadzki

Sie können versuchen, dieses Gradle-Plugin zu verwenden: https://github.com/arturdm/jacoco-Android-gradle-plugin

In der Antwort gibt es noch ein bisschen mehr https://stackoverflow.com/a/32572259/1711454 .

0