web-dev-qa-db-fra.com

Gradle Jacoco et JUnit5

Nous venons de porter nos tests unitaires sur JUnit5. En réalisant qu'il s'agit encore d'une adoption assez précoce, avec quelques indices sur Google.

Le plus difficile a été d'obtenir une couverture de code jacoco pour les tests Junit5 que nous utilisons sur Jenkins. Comme cela m’a pris presque une journée à comprendre, je pensais partager. Néanmoins, si vous connaissez une meilleure solution, je serais intéressé de le savoir!

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'

Ensuite, le problème semble être que junitPlatformTest, tel que défini dans le fichier org.junit.platform.gradle.plugin, est défini également À la fin de la phase de cycle de vie de Gradle et n'est donc pas connu lors de l'analyse du script.

Le hack suivant est nécessaire pour pouvoir toujours définir une tâche jacoco qui observe la tâche junitPlatformTest.

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

Enfin, il est nécessaire de configurer le plugin junitPlatform. Le code suivant autorise la configuration en ligne de commande des balises Junit 5 à exécuter: Vous pouvez exécuter tous les tests avec la balise 'unit' en exécutant:

gradle clean junitPlatformTest -PincludeTags=unit

Vous pouvez exécuter tous les tests pour lesquels il manque des balises unit et integ en utilisant

gradle clean junitPlatformTest -PexcludeTags=unit,integ

Si aucune balise n'est fournie, tous les tests seront exécutés (par défaut).

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
}
17
C. Ledergerber

Merci, le hack ressemble maintenant à ceci:

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
            })
}
5
C. Ledergerber

Peut également être résolu par injection directe d’agent:

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

alors le rapport sera disponible avec la tâche jacocoTestReport

4
lanwen

Pour obtenir une référence à la tâche junitPlatformTest, une autre option consiste à implémenter un bloc afterEvaluate dans le projet, comme suit:

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

  // do something with the junitPlatformTestTask
}

Voir mes commentaires sur GitHub pour JUnit 5 pour d'autres exemples.

1
Sam Brannen