如何在Gradle中使用JUnit 5?

How to use JUnit 5 with Gradle?

成功运行JUnit 4测试之后,我尝试将JUnit 5与Gradle结合使用。

预期结果:JUnit 4测试在输出中给出了很好的"通过",并且在build/reports/tests中给出了html报告。

实际结果:如下所示的JUnit 5测试不会输出除(...) build succesful之外的任何内容,尽管我知道该测试实际上并未运行,因为没有通过/跳过/失败的测试日志输出,并且在测试中放置fail构建成功。

我认为运行gradle test --info会产生Skipping task ':testClasses' as it has no actions.多数无关的输出。
令人惊讶的是,它还对build/test-results/test中的xml表示Executing task ':test'Generating HTML test report... Finished generating test html results,并且类似,虽然未生成xml,但html显示没有运行测试,也没有错误,并且测试确实没有运行。

我也认为非常有趣的是gradle test --debug

1
2
3
4
5
[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

而我唯一的测试包含

1
fail("test fails");

我觉得这很奇怪!

我的构建文件是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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"
    }
}

我的测试是

1
2
3
4
5
6
7
8
9
10
11
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");
    }
}

我的文件夹结构是使用包mypackage

1
2
3
4
5
6
7
java-template-project
--- src
    --- mypackage
        --- HelloWorld.java
--- test
    --- mypackage
        --- HelloWorldTest.java

在我使用的IntelliJ 2017.1.3中,模块结构如下所示

1
2
3
4
5
6
7
java-template-project
--- java-template-project_main
    --- src/mypackage
        --- HelloWorld(.java)
--- java-template-project_test
    --- test/mypackage
        --- HelloWorldTest(.java)

因为现在Gradle希望将源代码和测试放在自己的程序包中。

我尝试了什么

显然这不是关于此主题的第一个问题,我发现的所有相关问题都是

  • 在IntelliJ中运行jUnit 5测试的Gradle项目

    但是正如您所看到的,这是针对较旧版本的IntelliJ的,并且我已经在一个JUnit依赖项行中根据答案之一使用了IJ 2016.3.3及更高版本的语法,因此应该可以。

  • 使用gradle从intellij的JUnit 4升级到JUnit 5

    链接回上述问题,并链接至此Jetbrains博客,该博客使用与上述问题相同的内容。也链接到:

  • 将JUnit 5测试结果与Intellij测试报告集成
    在问题中,这也显示为依赖性

    1
    testRuntime("org.junit.vintage:junit-vintage-engine:5.0.0-M1")

    在IntelliJ中运行TestCase时,为什么JUnit Jupiter和JUnit Vintage分开的原因中有解释?
    好吧,当我运行它时,输出显示找不到该版本,但是根据Maven存储库,此版本适用于JUnit 5:

    1
    testRuntime("org.junit.vintage:junit-vintage-engine:4.12.0-M4")

    那里的答案说明您可以在IntelliJ中运行测试,因为更高的版本支持JUnit 5。我知道,当我从IntelliJ中运行时,测试运行良好。但是我想使用Gradle(和Travis,这需要依赖管理)。

  • 如何在junit 5 gradle测试报告中捕获stdout / stderr?

    我尝试使用

    1
    2
    testCompile("org.junit.platform:junit-platform-gradle-plugin:1.0.0-M3")
    testCompile("org.junit.jupiter:junit-jupiter-engine:5.0.0-M3")

    但结果没有改变。

    我的模板项目位于https://github.com/PHPirates/java-template-project,但是此问题应包含所有必要的信息。


新增:Gradle 4.6中的JUnit 5支持

正如从Gradle 4.6起的GitHub问题中所指出的那样,支持JUnit 5!
docs.gradle.org上的4.6官方发行说明(正在编辑最新版本,但请查看GitHub发布页面以确保您使用最新版本)。旧的设置仍然可以使用,但是使用它可以使构建文件更加整洁。

[2019年5月编辑]正如@deFreitas在他的回答中指出的那样,JUnit文档已得到改进,现在它们在https://github.com/junit-team/junit5-samples/tree/r5.4.0/junit5提供了一个完整的示例。 -jupiter-starter-gradle,尤其是在那里的build.gradle。幸运的是,事实证明它实际上与该答案相同。

更新摇篮

首先,请确保您使用的是最新的Gradle版本,并在其GitHub版本中检查最新版本。如果是例如4.6,请在项目位置gradlew wrapper --gradle-version=4.6中的终端中运行,或确保在gradle/wrapper/gradle-wrapper.properties文件:distributionUrl=https\\://services.gradle.org/distributions/gradle-4.6-all.zip中更新此行。

如何使用内置的JUnit 5

然后使用来自问题build.gradle的java文件,目录结构等(使用新的plugins块)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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有关绝对最低版本,请参见Ray的答案。

安卓系统

在Android上,我通过将以下内容添加到我的应用程序模块构建文件中,设法从问题中运行了JUnit 5测试。如您所见,依赖关系是相同的,但是我不需要useJUnitPlatform(),并且测试配置块略有不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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"
            }
        }
    }
}

但是,它仅对我执行Gradle test任务有效,而对运行check任务无效。像往常一样,我通过创建失败的测试来进行测试,然后尝试Gradle任务是否通过。


您需要两个JUnit版本的引擎,并且需要应用JUnit平台gradle插件。我没有在您的gradle文件中看到这一点。这是同时执行JUnit 4和5的有效gradle构建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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'
}

有关更多信息,请参见JUnit文档表单。


仅仅添加到知识库中,我就可以使用gradle 4.7进行以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
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()
}


由于github问题,JUnit 5的内置支持计划在Gradle 4.6中进行

因此,从gradle 4.6开始,您的预期结果必须与实际结果相同。

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于2018年2月16日发布,此版本提供了对junit 5的内置支持。

要启用junit 5支持,您需要更新gradle包装器:

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

并仅添加一行到build.gradle:

1
2
3
test {
    useJUnitPlatform()
}

查阅有关如何使用gradle的junit 5的junit官方文档。

build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

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

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


对于尝试将JUnit5与gradle版本4.10集成在一起的人来说,也许有一些帮助。

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

实际上,对于4.10,您不需要在build.gradle中添加此测试配置块即可启用JUnit5。

1
2
3
test {
    useJUnitPlatform()
}

仅通过添加jupitor-api和jupitor-engine的必要依赖项,它就可以正常工作。

我尝试浏览4.10的发行说明,但找不到有关此更改的任何信息。如果有人对它背后的"为什么"有所了解,那么也请给我启发。