Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have two sets of tests in JUnit Platform in Gradle

Tags:

java

junit

junit5

I'm using JUnit 5 platform via Gradle.

My current build file has configuration clause

junitPlatform {
    platformVersion '1.0.0-M5'
    logManager 'java.util.logging.LogManager'
    enableStandardTestTask true

    filters {
        tags {
            exclude 'integration-test'
        }
        packages {
            include 'com.scherule.calendaring'
        }
    }
}

That works fine. But I also need to run integration tests which require the application to be built, dockerized and run in background. So I should have second configuration like this which would be launched only then... how to achieve this? Normally I would extend Test task creating IntegrationTest task but it doesn't fit JUnit Platform where there is no simple task running tests...

I know I could do sth like this

task integrationTests(dependsOn: "startMyAppContainer") {
    doLast {
        def request = LauncherDiscoveryRequestBuilder.request()
                .selectors(selectPackage("com.scherule.calendaring"))
                .filters(includeClassNamePatterns(".*IntegrationTest"))
                .build()

        def launcher = LauncherFactory.create()

        def listener = new SummaryGeneratingListener()
        launcher.registerTestExecutionListeners(listener)
        launcher.execute(request)
    }

    finalizedBy(stopMyAppContainer)
}

but is there a simpler way? More consistent.

like image 882
kboom Avatar asked Jan 04 '23 16:01

kboom


1 Answers

This is not fully supported in Gradle with the JUnit5 plugin yet (though it's getting closer all the time). There are several workarounds. This is the one I use: it's a bit verbose, but it does the same thing as maven's test vs. verify.

Distinguish between (unit) test and integration test classes.

Gradle's main and test sourceSets are good as they are. Add a new integrationTest sourceSet that describes only your integration tests. You can use file names but that might mean you have to tweak the test sourceSet to skip files that it currently includes (in your example, you'd want to remove ".*IntegrationTest" from the test sourceSet and leave it only in the integrationTest sourceSet). So I prefer to use a root directory name that is different from the test sourceSet's one.

sourceSets {
  integrationTest {
    java {
      compileClasspath += main.output + test.output
      runtimeClasspath += main.output + test.output
      srcDir file('src/integrationTest/java')
    }
    resources.srcDir file('src/integrationTest/resources')
  }
}

Since we have the java plugin, this very nicely creates the integrationTestCompile and integrationTestRuntime functions for using with the dependencies block:

dependencies {
    // .. other stuff snipped out ..
    testCompile "org.assertj:assertj-core:${assertjVersion}"

    integrationTestCompile("org.springframework.boot:spring-boot-starter-test") {
        exclude module: 'junit:junit'
    }
}

Nice!

Add integration testing into the correct place in the build process

As you pointed out, you do need to have a task for running integration tests. You could use the launcher as in your example; I just delegate to the existing console runner in order to take advantage of the simple command line options.

def integrationTest = task('integrationTest',
                           type: JavaExec,
                           group: 'Verification') {
    description = 'Runs integration tests.'
    dependsOn testClasses
    shouldRunAfter test
    classpath = sourceSets.integrationTest.runtimeClasspath

    main = 'org.junit.platform.console.ConsoleLauncher'
    args = ['--scan-class-path',
            sourceSets.integrationTest.output.classesDir.absolutePath,
            '--reports-dir', "${buildDir}/test-results/junit-integrationTest"]
}

That task definition includes a dependsOn and shouldRunAfter, to make sure that when you run your integration tests, the unit tests are run first. To ensure that your integration tests are run when you ./gradlew check, you need to update the check task:

check {
  dependsOn integrationTest
}

Now you use ./gradlew test like ./mvnw test, and ./gradlew check like ./mvnw verify.

like image 75
Paul Hicks Avatar answered Jan 06 '23 06:01

Paul Hicks