如何将 JUnit 5 与 Gradle 一起使用?

Posted

技术标签:

【中文标题】如何将 JUnit 5 与 Gradle 一起使用?【英文标题】:How to use JUnit 5 with Gradle? 【发布时间】:2017-11-09 19:35:38 【问题描述】:

在成功运行 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 产生了

[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

而我唯一的测试包含

fail("test fails");

我觉得很奇怪!

我的构建文件是

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"
    

我的测试是

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

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

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

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

因为如今的 Gradle 想要将源代码和测试放在自己的包中。

我尝试了什么

显然这不是关于这个话题的第一个问题,我找到的所有相关问题都是

Gradle project running jUnit 5 tests in IntelliJ

但是正如您所看到的,这是针对旧版本的 IntelliJ 的,并且根据其中一个答案,我已经在使用 IJ 2016.3.3 及更高版本的语法,在一个 JUnit 依赖行中,所以应该没问题.

Upgrade from JUnit 4 to JUnit 5 in intellij with gradle

链接回上面的问题,并链接到这个Jetbrains blog,它使用与上面问题相同的行。还链接到:

Integrate JUnit 5 tests results with Intellij test report 在问题中,这也显示为依赖项

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

在Why were JUnit Jupiter and JUnit Vintage separated When I Running TestCase in IntelliJ? 中有解释 好吧,当我运行它时,输出显示它找不到这个版本,但根据Maven Repository 这个是针对 JUnit 5 的:

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

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

How to capture stdout/stderr in junit 5 gradle test report?

我尝试过使用

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,但这个问题应该包含所有必要的信息。

【问题讨论】:

遇到了同样的问题。发现应该从 'org.junit.jupiter.api' (Junit5 @Test) 导入 @Test 而不是 org.junit (Junit4 @Test) 【参考方案1】:

新功能:Gradle 4.6 中的 JUnit 5 支持

正如in this GitHub issue 所指出的,从 Gradle 4.6 开始支持 JUnit 5! 4.6 的官方发布说明(目前正在编辑最新版本,但请查看GitHub releases page 以确保您使用的是最新版本)at docs.gradle.org。旧的设置仍然可以工作,但使用它会使构建文件更干净。

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

更新 Gradle

首先,确保您使用的是最新版本的 Gradle,查看最新版本 at their GitHub releases。如果是例如 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

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

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's answer。

安卓

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

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 任务是通过还是失败。

【讨论】:

在撰写本文时,Gradle 内置支持仍然缺少一些可能对您很重要的功能。参见例如以下 github 问题:github.com/gradle/gradle/issues/4605 @johanneslink 感谢您的指出!这对我来说不是问题,但很高兴知道,并且看起来正在进行中:) 我们可以在没有额外库的情况下在android上使用JUnit5吗? @toffor 是的,我能够使用 Gradle check 任务从问题中运行测试(注意导入,它们与 JUnit 4 不同),只需将两个依赖项添加到我现有的 Android 应用程序。将其添加到答案中。 感谢您的快速回答。【参考方案2】:

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

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 doc 表格。

【讨论】:

【参考方案3】:

只是添加到知识库中,我刚刚得到以下与 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()

【讨论】:

感谢您添加更简单的示例!我认为使用plugins 块而不是apply plugin 是future,但目前并不重要。【参考方案4】:

由于 github issue 内置对 JUnit 5 的支持,计划用于 Gradle 4.6

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

预期结果:JUnit 4 测试在输出中给出了很好的“通过” 以及build/reports/tests 中的 html 报告。

更新:

gradle 4.6-rc-1 于 2018 年 2 月 16 日发布,此版本提供了对 junit 5 的内置支持。

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

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

在 build.gradle 中只添加一行:

test 
    useJUnitPlatform()

【讨论】:

【参考方案5】:

查看 junit official documentation 了解如何将 junit 5 与 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"
    

【讨论】:

感谢您的链接!我很高兴他们在提出这个问题后改进了他们的文档,我将在我的答案中添加一个链接。【参考方案6】:

也许对那些在尝试将 JUnit5 与 gradle 版本 4.10 集成时遇到此问题的人有所帮助。

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。

test 
    useJUnitPlatform()

只需添加必要的 jupitor-api 和 jupitor-engine 依赖项,它应该可以正常工作。

我尝试探索 4.10 的发行说明,但找不到有关此更改的任何信息。如果有人知道更多关于它背后的“为什么”,那么也请启发我。

【讨论】:

感谢您撰写答案,尽管我无法重现该错误,并且我仍然需要 useJUnitPlatform() 否则我的测试将无法运行(即使在 Gradle 5.0 上),我很好奇这里发生了什么.无论如何,希望这对其他人有用。 (编辑:也许您正在将 Gradle 用于 Android 项目。这可能是不同的。) 我遇到了类似的错误:Could not find method test() for arguments [build_ejzeh5kmeasn8zq3a46rzrkon$_run_closure4@49e05c95] on root project 'xxxxx' of type org.gradle.api.Project.,我认为这是因为我将test useJUnitPlatform() 放在subprojects ... 之外,如果我将它移到subprojects ... 内部,这个错误就消失了跨度>

以上是关于如何将 JUnit 5 与 Gradle 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Gradle中使用JUnit 5?

当 JUnit 5 没有 assertThat() 函数时,如何将 Hamcrest 与 JUnit 5 一起使用?

如何使用 Gradle 和 JUnit 5 仅运行特定测试?

是否可以将 apollo-android v2 与 Gradle 5 一起使用?

如何将 JUnit TemporaryFolder @Rule 与 Spring @Value 属性一起使用?

将 JUnit Hooks 与 Cucumber CLI Runner 一起使用