12

I tried looking for Jacoco offline instrumentation gradle script snippets but couldn't find one. Is it possible to do Jacoco offline instrumentation through gradle scripts ? If yes...An example of it would be greats. Thanks.

Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
karthik
  • 773
  • 2
  • 11
  • 19
  • IMHO there is no good reason to do the offline byte-code instrumentation anymore. Using a Java agent (like JaCoCo) is the most straightforward way. – G. Demecki Jan 05 '17 at 13:05
  • 1
    @G.Demecki I would usually agree, but there are Java toolchains out there that do not fully support on-the-fly instrumentation through Java agents (one example is the real-time capable JamaicaVM by Aicas). – AdrianoKF Aug 22 '17 at 11:59

4 Answers4

12

Here is an example of Gradle script that performs offline instrumentation using JaCoCo Ant Task:

apply plugin: 'java'

configurations {
  jacoco
  jacocoRuntime
}

dependencies {
  jacoco group: 'org.jacoco', name: 'org.jacoco.ant', version: '0.7.9', classifier: 'nodeps'
  jacocoRuntime group: 'org.jacoco', name: 'org.jacoco.agent', version: '0.7.9', classifier: 'runtime'
  testCompile 'junit:junit:4.12'
}

repositories {
  mavenCentral()
}

task instrument(dependsOn: ['classes']) {
  ext.outputDir = buildDir.path + '/classes-instrumented'
  doLast {
    ant.taskdef(name: 'instrument',
                classname: 'org.jacoco.ant.InstrumentTask',
                classpath: configurations.jacoco.asPath)
    ant.instrument(destdir: outputDir) {
      fileset(dir: sourceSets.main.output.classesDir)
    }
  }
}

gradle.taskGraph.whenReady { graph ->
  if (graph.hasTask(instrument)) {
    tasks.withType(Test) {
      doFirst {
        systemProperty 'jacoco-agent.destfile', buildDir.path + '/jacoco/tests.exec'
        classpath = files(instrument.outputDir) + classpath + configurations.jacocoRuntime
      }
    }
  }
}

task report(dependsOn: ['instrument', 'test']) {
  doLast {
    ant.taskdef(name: 'report',
                classname: 'org.jacoco.ant.ReportTask',
                classpath: configurations.jacoco.asPath)
    ant.report() {
      executiondata {
        ant.file(file: buildDir.path + '/jacoco/tests.exec')
      }
      structure(name: 'Example') {
         classfiles {
           fileset(dir: sourceSets.main.output.classesDir)
         }
         sourcefiles {
           fileset(dir: 'src/main/java')
         }
      }
      html(destdir: buildDir.path + '/reports/jacoco')
    }
  }
}
Godin
  • 9,801
  • 2
  • 39
  • 76
  • 1
    Can confirm this works. Any thought about getting this in the official plugin? – Kyle C Mar 22 '17 at 18:44
  • @KyleC, just for the reference: [Add offline instrumentation support to Gradle Jacoco plugin · Issue #2429 · gradle/gradle](https://github.com/gradle/gradle/issues/2429). – Sergey Vyacheslavovich Brunov Jan 17 '18 at 00:26
  • Doesn't work in gradle 5.X since sourceSets.main.output.classesDir is not available after gradle 4.X. – Chamin Wickramarathna Jun 10 '19 at 12:19
  • 3
    For gradle 5 and above replace `fileset(dir: sourceSets.main.output.classesDir)` with `sourceSets.main.output.classesDirs.each { fileset(dir: it) }`. I tested this with gradle 6.0.1 and it worked – Mohammad Alavi Dec 20 '19 at 08:09
  • hi @MohammadAlavi Could you please add your complete offline instrument script over here, as its not working for me – Min2 Aug 27 '20 at 10:18
  • 1
    @Min2 Please check out this repo https://github.com/AureaMohammadAlavi/gradle-jacoo-offline-instrumentation it contains a sample project that uses jacoco offline instrumentation – Mohammad Alavi Aug 28 '20 at 07:52
4

classesDir is not available in Gradle 5 this offline instrumentation code worked for me on Gradle 5.1.1

 task instrument(dependsOn: [classes, project.configurations.jacocoAnt]) {

 inputs.files classes.outputs.files
 File outputDir = new File(project.buildDir, 'instrumentedClasses')
 outputs.dir outputDir
 doFirst {
     project.delete(outputDir)
     ant.taskdef(
             resource: 'org/jacoco/ant/antlib.xml',
             classpath: project.configurations.jacocoAnt.asPath,
             uri: 'jacoco'
     )
     def instrumented = false
     if (file(sourceSets.main.java.outputDir).exists()) {
         def instrumentedClassedDir = "${outputDir}/${sourceSets.main.java}"
         ant.'jacoco:instrument'(destdir: instrumentedClassedDir) {
             fileset(dir: sourceSets.main.java.outputDir, includes: '**/*.class')
         }
         //Replace the classes dir in the test classpath with the instrumented one
         sourceSets.test.runtimeClasspath -= files(sourceSets.main.java.outputDir)
         sourceSets.test.runtimeClasspath += files(instrumentedClassedDir)
         instrumented = true
     }
     if (instrumented) {
         test.jvmArgs += '-noverify'
     }
 }
}


test.dependsOn instrument

The above code is taken from the link https://github.com/esdk/g30l0/commit/82af4c9aad50aadc40d940471fe1b934473170c7 pease follow for more information.

Pravanjan
  • 698
  • 7
  • 16
1

The answer https://stackoverflow.com/a/42238982/2689114 works for me(with some adapting to a newer gradle version).

If you have multi-module gradle project, then you should add some extra configuration to support cross-module code coverage.

For more details see Cross-module code coverage with Jacoco offline instrumentation in gradle mutlimodule project

Also, there is a working example: https://github.com/SurpSG/jacoco-offline-instrumentation

UPD: there is alternative jacoco gradle plugin that uses jacoco in offline mode

SergiiGnatiuk
  • 522
  • 7
  • 13
-1

The gradle jacoco plugin doesn't support offline instrumentation, it always does online instrumentation via the java agent.

If the ant jacoco plugin supports offline instrumentation that's likely the best way to get offline instrumentation working in gradle

lance-java
  • 25,497
  • 4
  • 59
  • 101
  • could you point the script/snippet from doc where he is doing offline instrumentation....I couldn't figure out the script that does offline instrumentation. I didn't get where he is doing that in examples. If you could through the snippets that would be great. – karthik Dec 29 '16 at 03:39
  • 1
    Instrumentation with a Java agent - is on-the-fly instrumentation. Offline instrumentation doesn't require java agent. And I doubt that Gradle plugin supports this, and that's probably why you @karthik can't find examples. – Godin Dec 29 '16 at 08:51
  • @LanceJava I guess you can edit an answer to get rid of this confusion ;) – Godin Dec 29 '16 at 11:41
  • Jacoco supports offline instrumentation : http://www.jacoco.org/jacoco/trunk/doc/offline.html , but the gradle plugin doesn't leverage it, i.e. you can't have a Gradle task which will instrument classes, unless you wrap the Ant library altogether. – Patrice M. Jan 11 '17 at 17:51