How to use JUnit 5 with Gradle?

GradleJunitbuild.gradleJunit5

Gradle Problem Overview


I am trying to use JUnit 5 with Gradle after I succeeded in running a JUnit 4 test.

Expected result: Tthe JUnit 4 test gave a nice 'passed' in the output and an html report in build/reports/tests.

Actual result: The JUnit 5 test as below does not output anything besides (...) build succesful, while I know the test is not actually run since there is no test log output passed/skipped/failed, and putting a fail in the test keeps the build successful.

Running gradle test --info yields Skipping task ':testClasses' as it has no actions. among a lot of I think mostly unrelevant output. Surprisingly, it also says Executing task ':test' and Generating HTML test report... Finished generating test html results and similar for the xml in build/test-results/test, while the xml is not generated, the html shows no tests run and no errors, and the test is indeed not run.

What I also think very interesting, is that gradle test --debug yields

[TestEventLogger] Gradle Test Run :test STARTED
[org.gradle.api.internal.tasks.testing.junit.JUnitDetector] test-class-
scan : failed to scan parent class java/lang/Object, could not find the class file
[TestEventLogger]
[TestEventLogger] Gradle Test Run :test PASSED

while my only test contains

fail("test fails");

which I think is very strange!

My build file is

apply plugin: 'java'

test {
    dependsOn 'cleanTest' // run tests every time

}

sourceSets {
    main {
        java {
            srcDirs 'src'
        }
    }
    test {
        java {
            srcDirs 'test'
        }
    }
}

repositories {
    mavenCentral()
}

dependencies {
    // when using this, it worked with a junit 4 test
//    testCompile 'junit:junit:4.10'
    // this should be needed for junit 5 (using M4 is required since IJ 2017.1.2
    testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0-M4")
}

test {
    testLogging {
        events "passed", "skipped", "failed"
    }
}

My test is

package mypackage;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class HelloWorldTest {
    @Test
    public void testHelloWorld(){
        assertEquals(2, 1+1, "message");
    }
}

My folder structure is, using package mypackage,

java-template-project
--- src
    --- mypackage
        --- HelloWorld.java
--- test
    --- mypackage
        --- HelloWorldTest.java

and in IntelliJ 2017.1.3, which I am using, the module structure looks like this

java-template-project
--- java-template-project_main
    --- src/mypackage
        --- HelloWorld(.java)
--- java-template-project_test
    --- test/mypackage
        --- HelloWorldTest(.java)

because Gradle nowadays wants the source and tests in their own package.

What I tried

Obviously this is not the first question about this topic, all the relevant questions I found are

Gradle Solutions


Solution 1 - Gradle

New: JUnit 5 support in Gradle 4.6

As pointed out in this GitHub issue from Gradle 4.6 onwards JUnit 5 is supported! Official release notes of 4.6 (at the moment of editing the latest, but check the GitHub releases page to make sure you use the latest version) at docs.gradle.org. The old setup will still work, but using this makes the build file a lot cleaner.

[Edit May 2019] As @deFreitas pointed out in his answer, the JUnit documentation has improved and now they provide a complete example at https://github.com/junit-team/junit5-samples/tree/r5.4.0/junit5-jupiter-starter-gradle, see especially the build.gradle there. Fortunately it turns out to be effectively the same as the one from this answer.

Update Gradle

First, make sure you are using the latest Gradle version, check latest releases at their GitHub releases. If that is for example 4.6, run in a terminal in your project location gradlew wrapper --gradle-version=4.6 or make sure to update this line in your gradle/wrapper/gradle-wrapper.properties file: distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip.

How to use the built-in JUnit 5

Then with the java files, directory structure etc. from the question the build.gradle file will be (using the new plugins block)

plugins {
    id 'java'
}

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.3'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.0.3'
}

// These lines can be removed when you use the default directories src/main/kotlin and src/test/kotlin
sourceSets {
    main.java.srcDirs += 'src'
    main.resources.srcDirs += 'src'
    test.java.srcDirs += 'test'
    test.resources.srcDirs += 'test'
}

// Java target version
sourceCompatibility = 1.8

test {
    // Enable JUnit 5 (Gradle 4.6+).
    useJUnitPlatform()

    // Always run tests, even when nothing changed.
    dependsOn 'cleanTest'

    // Show test results.
    testLogging {
        events "passed", "skipped", "failed"
    }
}

PS For the absolute minimal version, see Ray's answer.

Android

On Android I managed to run the JUnit 5 test from the question by adding the following to my app module build file. As you can see the dependencies are the same, but I didn't need useJUnitPlatform() and the test configuration block is slightly different.

apply plugin: 'com.android.application'
// In fact I am not sure you need this, but I had it included to run Spek tests anyway
apply plugin: 'de.mannodermaus.android-junit5' 

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}


android {
    // I'm omitting your other configurations like compileSdkVersion, buildTypes etc.

    testOptions {
        unitTests.all {

            // Always run tests, even when nothing changed.
            dependsOn 'clean'

            // Show test results.
            testLogging {
                events "passed", "skipped", "failed"
            }
        }
    }
}

however it only works for me when I execute the Gradle test task, not when I run the check task. As usual, I test this by creating a failing test and then I try if the Gradle task passes or fails.

Solution 2 - Gradle

You need the engines for both JUnit versions, and you need to apply the JUnit platform gradle plugin. I do not see that in your gradle file. Here is a working gradle build executing both JUnit 4 and 5:

buildscript {
    repositories {
	    mavenCentral()
	}
	dependencies {
		classpath ("org.junit.platform:junit-platform-gradle-plugin:1.0.0-M4")
    }
}

apply plugin: 'org.junit.platform.gradle.plugin'
...

dependencies {
...
	testCompile("junit:junit:4.12")
	testRuntime("org.junit.vintage:junit-vintage-engine:4.12.0-M4")

	testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0-M4")
    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.0.0-M4")

	// Enable use of the JUnitPlatform Runner within the IDE
    testCompile("org.junit.platform:junit-platform-runner:1.0.0-M4")
}

junitPlatform {
    details 'tree'
}

See the JUnit doc form more information on that.

Solution 3 - Gradle

just adding to the knowledge base, i just got the following to work with gradle 4.7:

apply plugin: 'java'
repositories {
    jcenter()
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.1'
}

test {
    useJUnitPlatform()
}

Solution 4 - Gradle

Due to github issue built-in support for JUnit 5, scheduled for Gradle 4.6

Thus since gradle 4.6 your expected result have to be the same as actual result.

> Expected result: Tthe JUnit 4 test gave a nice 'passed' in the output > and an html report in build/reports/tests.

UPD:

gradle 4.6-rc-1 was released on 16th of February 2018 and this version provides the built-in support for junit 5.

To enable junit 5 support you need to update gradle wrapper:

gradle wrapper --gradle-version=4.6-rc-1

and add just one line to build.gradle:

test {
    useJUnitPlatform()
}

Solution 5 - Gradle

Checkout junit official documentation of how to use junit 5 with gradle.

build.gradle

plugins {
	id 'java'
}

repositories {
	mavenCentral()
}

dependencies {
	testImplementation('org.junit.jupiter:junit-jupiter:5.4.0')
}

test {
	useJUnitPlatform()
	testLogging {
		events "passed", "skipped", "failed"
	}
}

Solution 6 - Gradle

Maybe something helpful for those who were struck with this problem when trying to integrate JUnit5 with gradle version 4.10.

Could not find method test() for arguments [build_dzas89s5z18l3bfyn6b3q0dxv$_run_closure2$_closure9@8e60c6] on project ':app' of type org.gradle.api.Project.

Actually, with 4.10 you don't need to add this test configuration block in build.gradle to enable JUnit5.

test {
    useJUnitPlatform()
}

It should work fine just by adding the necessary dependencies of jupitor-api and jupitor-engine.

I tried to explore release notes of 4.10 but couldn't find anything about this change. If someone knows more about the "Why" behind it then please englighten me as well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPHPirateView Question on Stackoverflow
Solution 1 - GradlePHPirateView Answer on Stackoverflow
Solution 2 - GradleRalf StuckertView Answer on Stackoverflow
Solution 3 - GradleRay TayekView Answer on Stackoverflow
Solution 4 - GradleyanefedorView Answer on Stackoverflow
Solution 5 - GradledeFreitasView Answer on Stackoverflow
Solution 6 - GradleWahib Ul HaqView Answer on Stackoverflow