简体   繁体   中英

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
}

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
            })
}

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

To get a reference to the junitPlatformTest task, another option is to implement an afterEvaluate block in the project like this:

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

  // do something with the junitPlatformTestTask
}

See my comments on GitHub for JUnit 5 for further examples.

You just need to add @RunWith(JUnitPlatform.class) to your package

@RunWith(JUnitPlatform.class)
public class ClassTest {
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM