JUnit 5 under Gradle with multiple source sets

2019-04-07 12:25发布

问题:

I've got a project I'm putting together that I want to use JUnit 5 for. I've got this working fine for Unit Tests already.

I do however have multiple test source sets - I've got an additional one for Acceptance Tests. I'm struggling to work out how to get JUnit 5 to run the Unit Tests - defined in src/test - in one task and the Acceptance Tests - defined in the "acceptanceTest" sourceSet and located in "src/acceptance" - in another task.

I have previously got this working with JUnit 4 and Cucumber, but the JUnit 5 plugin doesn't seem to want to work like this.

build.gradle:

buildscript {
  ext {
    jackson_version = "2.9.0.pr4"
    // IntelliJ needs M4
    junitJupiter_version = "5.0.0-M4"
    junitPlatform_version = "1.0.0-M4"
    kotlin_version = "1.1.3-2"
    slf4j_version = "1.7.25"
    spring_version = "4.3.10.RELEASE"
    springBoot_version = "1.5.4.RELEASE"
    springBootAdmin_version = "1.5.2"

    runAcceptance = System.properties['noAcceptance'] == null
  }

  repositories {
    mavenCentral()
    jcenter()
  }

  dependencies {
    classpath "com.github.ben-manes:gradle-versions-plugin:0.15.0"
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
    classpath "org.junit.platform:junit-platform-gradle-plugin:$junitPlatform_version"
    classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBoot_version"
  }
}

plugins {
  id "com.github.ben-manes.versions" version "0.15.0"
}

apply plugin: "com.github.ben-manes.versions"
apply plugin: "kotlin"
apply plugin: "kotlin-spring"
apply plugin: "org.junit.platform.gradle.plugin"
apply plugin: "org.springframework.boot"
apply plugin: "war"

repositories {
  mavenCentral()
  maven { url "https://jitpack.io" }
}

sourceSets {
  acceptanceTest {
    kotlin {
      compileClasspath += main.output + test.output
      runtimeClasspath += main.output + test.output
      srcDir file('src/acceptance/kotlin')
    }
    resources.srcDir file('src/acceptance/resources')
  }
}

configurations {
  acceptanceTestCompile.extendsFrom testCompile
  acceptanceTestRuntime.extendsFrom testRuntime
}

dependencies {
  compile "com.graphql-java:graphql-java-tools:3.1.3"
  compile "com.graphql-java:graphql-spring-boot-starter:3.5.0"
  compile "com.zaxxer:HikariCP:2.6.3"
  compile("de.codecentric:spring-boot-admin-server:$springBootAdmin_version") {
      exclude group: "junit", module: "junit"
  }
  compile("de.codecentric:spring-boot-admin-server-ui:$springBootAdmin_version") {
      exclude group: "junit", module: "junit"
  }
  compile("de.codecentric:spring-boot-admin-starter-client:$springBootAdmin_version") {
      exclude group: "junit", module: "junit"
  }
  compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
  compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
  compile "org.slf4j:slf4j-api:$slf4j_version"
  compile "org.springframework:spring-jdbc:$spring_version"
  compile "org.springframework.boot:spring-boot-starter-web:$springBoot_version"
  compile "org.springframework.boot:spring-boot-starter-actuator:$springBoot_version"
  compile "ru.yandex.qatools.embed:postgresql-embedded:2.2"

  runtime "ch.qos.logback:logback-classic:1.2.3"
  runtime "org.jolokia:jolokia-core:1.3.7"
  runtime "org.liquibase:liquibase-core:3.5.3"
  runtime "org.postgresql:postgresql:42.1.3"
  runtime "org.slf4j:jcl-over-slf4j:$slf4j_version"
  runtime "org.slf4j:jul-to-slf4j:$slf4j_version"

  testCompile "com.github.sbrannen:spring-test-junit5:1.0.0.M4"
  testCompile "com.nhaarman:mockito-kotlin:1.5.0"
  testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version") {
      exclude group: "junit", module: "junit"
  }
  testCompile "org.junit.jupiter:junit-jupiter-api:$junitJupiter_version"

  testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitJupiter_version"

  acceptanceTestCompile "org.springframework.boot:spring-boot-starter-test:$springBoot_version"
}

task acceptanceTest(type: Test) {
  testClassesDirs = sourceSets.acceptanceTest.output.classesDirs
  classpath = sourceSets.acceptanceTest.runtimeClasspath
  outputs.upToDateWhen { false }
}

if (ext.runAcceptance) {
  check.dependsOn acceptanceTest
}
acceptanceTest.mustRunAfter test

task wrapper(type: Wrapper) {
  gradleVersion = "4.0"
}

回答1:

Since Gradle 4.6 the gradle Java plugin has JUnit 5 support

So once you have configured the test source sets, the setup is as simple as follows - for my test and intTest test tasks I just need to configure this to use JUnit5:

apply plugin: 'java'

test {
    useJUnitPlatform()
}

intTest {
    useJUnitPlatform()
}

dependencies {
    testCompile("org.junit.jupiter:junit-jupiter-api:5.1.0")
    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.1.0")

}


回答2:

The JUnit 5 plugin only creates one task - junitPlatformTest, and bases it on the junitPlatform extension.

If you want to run acceptance tests, or any other type of tests in another source set independently, you'll need to create your own JavaExec task, like the plugin does.

See: https://github.com/junit-team/junit5/blob/master/junit-platform-gradle-plugin/src/main/groovy/org/junit/platform/gradle/plugin/JUnitPlatformPlugin.groovy#L66



回答3:

To refine existing answers, you need to configure each of your Test-type tasks to include useJUnitPlatform(). In your concrete example this would look like

task acceptanceTest(type: Test) {
  useJUnitPlatform()
  testClassesDirs = sourceSets.acceptanceTest.output.classesDirs
  classpath = sourceSets.acceptanceTest.runtimeClasspath
  outputs.upToDateWhen { false }
}

You can also do this centrally via

tasks.withType(Test) {
    useJUnitPlatform()
}


回答4:

You might want to create a task like this:

task e2eTest(
        type: JavaExec,
        description: 'Runs the e2e tests.',
        group: 'Verification'
) {
    dependsOn testClasses
    shouldRunAfter test

    classpath = sourceSets.e2e.runtimeClasspath

    main = 'org.junit.platform.console.ConsoleLauncher'
    args = ['--scan-class-path',
            sourceSets.e2e.output.getClassesDirs().asPath,
            '--reports-dir', "${buildDir}/test-results/junit-e2e"]
}