4

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.

1
  • Maven has the ability to differentiate unit tests and integration tests, based on class name. See discussion at maven.apache.org/surefire/maven-failsafe-plugin I am not familiar with Gradle, but I have faith that it has to have a similar mechanism. Commented Jul 27, 2017 at 19:59

1 Answer 1

11

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.

Sign up to request clarification or add additional context in comments.

1 Comment

This is very nice & clean, thank you sir! In case anyone wondered if you're dockerizing your app its best to use the very same container to run for integration tests using github.com/bmuschko/gradle-docker-plugin. You can then easily start and stop container after tests. The question remains how to allocate first free port from ephemeral range... do anyone know?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.