generate code coverage on JenkinsPipelineUnit tests

1.1k Views Asked by At

I am building a jenkins shared library (in groovy) and testing this with JenkinsPipelineUnit and in gradle. Running ./gradlew test jacocoTestReport runs fine, but the report is almost empty (just headers); no coverage is present.

Here are the relevant parts of my build.gradle:

plugins {
    id 'groovy'
    id 'application'
    id 'jacoco'
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.5.4'
    testCompile 'junit:junit:4.12'
    testCompile 'com.lesfurets:jenkins-pipeline-unit:1.1.1-custom' // minor adaptations, but that's another story
}

test {
    systemProperty "pipeline.stack.write", System.getProperty("pipeline.stack.write")
}

jacocoTestReport {
    group = "Reporting"
    reports {
        xml.enabled true
        csv.enabled false
    }
    additionalSourceDirs = files('vars')
    sourceDirectories = fileTree(dir: 'vars')
}

I think the trouble resides in the fact that my "source" files reside in the vars directory and not in src/groovy as expected in a normal groovy project. This is however a requirement for a Jenkins shared library.

I tried specifying

sourceSets {
    main {
        groovy {
            srcDir 'vars'
        }
    }
}

but then gradle would start compiling this shared library while it's supposed to be loaded upon use; and this breaks everything...

My folder structure looks like this:

├── build.gradle
├── src
│   └── test
│       ├── groovy
│       │   └── TestSimplePipeline.groovy
│       └── resources
│           └── simplePipeline.jenkins
└── vars
    ├── MyPipeline.groovy
    └── sh.groovy

I think my problem is linked to https://github.com/jenkinsci/JenkinsPipelineUnit/issues/119 , but I wouldn't know how to use the changes proposed for maven in gradle (not even sure they apply to jacoco).

1

There are 1 best solutions below

0
On

The problem is that JenkinsPipelineUnit evaluates your scripts in runtime. It means jacoco agent cannot instrument the byte-code generated in runtime.

To overcome this issue you need to do two changes.

  1. Use jacoco offline instrumentalisation

In my case I used maven, so I cannot provide you with a specific example of a gradle configuration.

  1. Load compiled classes instead of groovy scripts in your test. Something like this:
def scriptClass = helper.getBaseClassloader().loadClass("fooScript")
def binding = new Binding()
script = InvokerHelper.createScript(scriptClass, binding)
InterceptingGCL.interceptClassMethods(script.metaClass, helper, binding)

Here fooScript is the name of the class (say you have a source file called fooScript.groovy in this case).

Now you can call methods of this class via

def result = script.invokeMethod(methodName, args)