2016-03-01 10 views
16

Ich wollte Code-Coverage-Berichte zu meinen JUnit-Tests in meinem Android-Projekt erstellen, also habe ich das JaCoCo-Gradle-Plugin hinzugefügt. Das ist meine Projektebene build.gradle Datei:JaCoCo funktioniert nicht mit Robolectric-Tests

apply plugin: 'jacoco' 

buildscript { 
    repositories { 
     jcenter() 
    } 
    dependencies { 
     classpath 'com.android.tools.build:gradle:2.0.0-beta6' 
     classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' 
    } 
} 

allprojects { 
    repositories { 
     jcenter() 
     maven { url "https://oss.sonatype.org/content/repositories/snapshots" } 
    } 
} 

task clean(type: Delete) { 
    delete rootProject.buildDir 
} 

subprojects { prj -> 
    apply plugin: 'jacoco' 

    jacoco { 
     toolVersion '0.7.6.201602180812' 
    } 

    task jacocoReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') { 
     group = 'Reporting' 
     description = 'Generate Jacoco coverage reports after running tests.' 

     reports { 
      xml { 
       enabled = true 
       destination "${prj.buildDir}/reports/jacoco/jacoco.xml" 
      } 
      html { 
       enabled = true 
       destination "${prj.buildDir}/reports/jacoco" 
      } 
     } 

     classDirectories = fileTree(
       dir: 'build/intermediates/classes/debug', 
       excludes: [ 
         '**/R*.class', 
         '**/BuildConfig*', 
         '**/*$$*' 
       ] 
     ) 

     sourceDirectories = files('src/main/java') 
     executionData = files('build/jacoco/testDebugUnitTest.exec') 

     doFirst { 
      files('build/intermediates/classes/debug').getFiles().each { file -> 
       if (file.name.contains('$$')) { 
        file.renameTo(file.path.replace('$$', '$')) 
       } 
      } 
     } 
    } 
} 

jacoco { 
    toolVersion '0.7.6.201602180812' 
} 

task jacocoFullReport(type: JacocoReport, group: 'Coverage reports') { 
    group = 'Reporting' 
    description = 'Generates an aggregate report from all subprojects' 

    //noinspection GrUnresolvedAccess 
    dependsOn(subprojects.jacocoReport) 

    additionalSourceDirs = project.files(subprojects.jacocoReport.sourceDirectories) 
    sourceDirectories = project.files(subprojects.jacocoReport.sourceDirectories) 
    classDirectories = project.files(subprojects.jacocoReport.classDirectories) 
    executionData = project.files(subprojects.jacocoReport.executionData) 

    reports { 
     xml { 
      enabled = true 
      destination "${buildDir}/reports/jacoco/full/jacoco.xml" 
     } 
     html { 
      enabled = true 
      destination "${buildDir}/reports/jacoco/full" 
     } 
    } 

    doFirst { 
     //noinspection GroovyAssignabilityCheck 
     executionData = files(executionData.findAll { it.exists() }) 
    } 
} 

Es funktioniert großartig von ./gradlew jacocoFullReport laufen. Aber leider ist die Abdeckung für die Tests, die mit der RobolectricTestRunner ausgeführt werden, nicht gemeldet (Anweisungen, die offensichtlich in den Tests aufgerufen werden, werden nicht als abgedeckt gemeldet). Tests mit @RunWith Annotation oder Lauf mit MockitoJUnitTestRunner Berichterstattung Abdeckung gut.

Jede Hilfe wäre willkommen, um dieses Problem zu beheben.

Update 1: Ich bemerkte, dass ich die RobolectricGradleTestRunner verwenden sollte. Aber es hat nicht geholfen.

+0

Ich möchte sagen, dass dies auf jeden Fall möglich ist, aber ich habe keine Ahnung, wie man es beheben. Ich habe es geschafft, Code Coverage für Robolectric in einem alten Job zu bekommen, aber das war vor einem Jahr und ich habe keinen Zugriff mehr auf diesen Code. Tut mir leid, ich kann nicht mehr helfen! –

+0

'testCoverageEnabled' in späteren Versionen von Gradle verwendet Jacoco, du musst kein Plugin anwenden. Versuche es ohne das Plugin. –

+0

@NikolaDespotoski Ich glaube, das Setzen von testCoverageEnabled auf "True" funktioniert nur mit Android-Instrumentierungstests, für die ein verbundenes Gerät erforderlich ist. Und das versuche ich mit Robolectric zu vermeiden. – Longi

Antwort

14

Es ist Problem mit der möglichen Abhilfe bekannt - https://github.com/jacoco/jacoco/pull/288

oder degradieren jacoco Version 0.7.1.201405082137

UPDATE

Die Abhilfemaßnahme nicht mehr benötigt wird. Sie müssen Gradle Version 2.13 und jacoco Version 0.7.6.201602180812 verwenden.

Aktualisierung von Stamm build.gradle:

buildscript { 
    dependencies { 
     classpath 'org.jacoco:org.jacoco.core:0.7.6.201602180812' 
    } 
} 

task wrapper(type: Wrapper) { 
    gradleVersion = '2.13' 
} 

Run ./gradlew wrapper

Update-Projekt build.gradle:

apply plugin: 'jacoco' 

android { 
    testOptions { 
    unitTests.all { 
     jacoco { 
     includeNoLocationClasses = true 
     } 
    } 
    } 
} 
+1

Leider scheint der Workaround für mich nicht zu funktionieren. – Longi

+0

In diesem Fall, wenn es für Sie nicht wichtig ist, dann niedrigere Version von jacoco zu '0.7.1.201405082137'. Es kann immer noch das Problem sein, wenn Sie jenkins neueste jacoco Plugin verwenden. Downgrade-Version von es auch auf etwas "1.8" –

+0

Downgrading jacoco hat den Trick gemacht. Ich benutze Travis-Ci und es gibt kein Problem damit. – Longi

1

hatte ich das gleiche Problem. Ich habe die jacoco-Plugin-Version geändert und die Eigenschaft includeolocationclasses hinzugefügt. Hier ist die Arbeits jacoco.gradle Datei (Ich verwende gradle Wrapper 2.14.1):

apply plugin: 'jacoco' 

jacoco { 
    toolVersion = "0.7.6.201602180812" 
} 

android { 
    testOptions { 
     unitTests.all { 
      jacoco { 
       includeNoLocationClasses = true 
      } 
     } 
    } 
} 

project.afterEvaluate { 
    // Grab all build types and product flavors 
    def buildTypes = android.buildTypes.collect { type -> type.name } 
    def productFlavors = android.productFlavors.collect { flavor -> flavor.name } 
    println(buildTypes) 
    println(productFlavors) 
    // When no product flavors defined, use empty 
    if (!productFlavors) productFlavors.add('') 

    productFlavors.each { productFlavorName -> 
     buildTypes.each { buildTypeName -> 
      def sourceName, sourcePath 
      if (!productFlavorName) { 
       sourceName = sourcePath = "${buildTypeName}" 
      } else { 
       sourceName = "${productFlavorName}${buildTypeName.capitalize()}" 
       sourcePath = "${productFlavorName}/${buildTypeName}" 
      } 
      def testTaskName = "test${sourceName.capitalize()}UnitTest" 
      println("SourceName:${sourceName}") 
      println("SourcePath:${sourcePath}") 
      println("testTaskName:${testTaskName}") 
      // Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest' 
      task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") { 
       group = "Reporting" 
       description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build." 

       classDirectories = fileTree(
         dir: "${project.buildDir}/intermediates/classes/${sourcePath}", 
         excludes: ['**/R.class', 
            '**/R$*.class', 
            '**/*$ViewInjector*.*', 
            '**/*$ViewBinder*.*', 
            '**/BuildConfig.*', 
            '**/Manifest*.*'] 
       ) 

       def coverageSourceDirs = [ 
         "src/main/java", 
         "src/$productFlavorName/java", 
         "src/$buildTypeName/java" 
       ] 
       additionalSourceDirs = files(coverageSourceDirs) 
       sourceDirectories = files(coverageSourceDirs) 
       executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec") 
       println("${project.buildDir}/jacoco/${testTaskName}.exec") 
       reports { 
        xml.enabled = true 
        html.enabled = true 
       } 
      } 
     } 
    } 
}