Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle Jacoco and JUnit5

We just ported our unit tests to JUnit5. Realizing that this is still rather early adoption with little hints on google.

The most challenging was to get jacoco code coverage for the Junit5 tests which we use on jenkins. Since this took me almost a day to figure out, I thought I share. Nevertheless, if you know of a better solution I would be interested to know!

buildscript {

    dependencies {
       // dependency needed to run junit 5 tests
       classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2'
   }
}

// include the jacoco plugin
plugins {
    id 'jacoco'
}

dependencies {
    testCompile "org.junit.jupiter:junit-jupiter-api:5.0.0-M2"
    runtime "org.junit.jupiter:junit-jupiter-engine:5.0.0-M2"
    runtime "org.junit.vintage:junit-vintage-engine:4.12.0-M2"
}

apply plugin: 'org.junit.platform.gradle.plugin'

Then the problem seems to be that junitPlatformTest as defined in the org.junit.platform.gradle.plugin is defined too late in the gradle lifecycle phase and hence is unknown when the script is parsed.

The following hack is needed in order to still be able to define a jacoco task which observes the junitPlatformTest task.

tasks.whenTaskAdded { task ->
    if (task.name.equals('junitPlatformTest')) {
        System.out.println("ADDING TASK " + task.getName() + " to the project!")

    // configure jacoco to analyze the junitPlatformTest task
    jacoco {
        // this tool version is compatible with
        toolVersion = "0.7.6.201602180812"
        applyTo task
    }

    // create junit platform jacoco task
    project.task(type: JacocoReport, "junitPlatformJacocoReport",
            {
                sourceDirectories = files("./src/main")
                classDirectories = files("$buildDir/classes/main")
                executionData task
            })
    }
}

Finally it is necessary to configure the junitPlatform plugin. The following code allows command line configuration of which junit 5 tags shall be run: You can run all tests with 'unit' tag by running:

gradle clean junitPlatformTest -PincludeTags=unit

You can run all tests which are missing both unit and integ tag using

gradle clean junitPlatformTest -PexcludeTags=unit,integ

If no tags are provided all tests will be run (default).

junitPlatform {

    engines {
        include 'junit-jupiter'
        include 'junit-vintage'
    }

    reportsDir = file("$buildDir/test-results")

    tags {
        if (project.hasProperty('includeTags')) {
            for (String t : includeTags.split(',')) {
                include t
            }
        }

        if (project.hasProperty('excludeTags')) {
            for (String t : excludeTags.split(',')) {
                exclude t
            }
        }
    }

    enableStandardTestTask false
}
like image 263
C. Ledergerber Avatar asked Sep 07 '16 06:09

C. Ledergerber


People also ask

Is Jupiter a junit5?

Jupiter. JUnit Jupiter is the combination of the new programming model and extension model for writing tests and extensions in JUnit 5. The Jupiter sub-project provides a TestEngine for running Jupiter based tests on the platform. Vintage.

What is jacocoTestReport?

JaCoCo Report configurationThe JacocoReport task can be used to generate code coverage reports in different formats. It implements the standard Gradle type Reporting and exposes a report container of type JacocoReportsContainer. Example 4. Configuring test task. build.gradle.


2 Answers

Thank you, so the hack now looks like this:

project.afterEvaluate {
    def junitPlatformTestTask = project.tasks.getByName('junitPlatformTest')

    // configure jacoco to analyze the junitPlatformTest task
    jacoco {
        // this tool version is compatible with
        toolVersion = "0.7.6.201602180812"
        applyTo junitPlatformTestTask
    }

    // create junit platform jacoco task
    project.task(type: JacocoReport, "junitPlatformJacocoReport",
            {
                sourceDirectories = files("./src/main")
                classDirectories = files("$buildDir/classes/main")
                executionData junitPlatformTestTask
            })
}
like image 71
C. Ledergerber Avatar answered Oct 04 '22 16:10

C. Ledergerber


Can be also resolved with direct agent injection:

subprojects {
   apply plugin: 'jacoco'

   jacoco {
        toolVersion = "0.7.9"
   }

   configurations {
        testAgent {
            transitive = false
        }
   }

   dependencies {
        testAgent("org.jacoco:org.jacoco.agent:0.7.9:runtime")
   }

   tasks.withType(JavaExec) {
        if (it.name == 'junitPlatformTest') {
            doFirst {
                jvmArgs "-javaagent:${configurations.testAgent.singleFile}=destfile=${project.buildDir.name}/jacoco/test.exec"
            }
        }
    }
}

then report will be available with jacocoTestReport task

like image 29
lanwen Avatar answered Oct 04 '22 15:10

lanwen