【问题标题】:Simple modern Gradle configuration to mimic default Maven Failsafe configuration模仿默认 Maven Failsafe 配置的简单现代 Gradle 配置
【发布时间】:2021-02-09 00:49:27
【问题描述】:

什么是配置 Gradle 的简单(但现代的最佳实践)方法,以便它允许我运行类似于默认 Maven Failsafe configuration 的工作方式的集成测试?我已经阅读了Gradle docs for tests——尤其是Gradle docs for integration tests——但它们看起来相当复杂(与 Maven Failsafe 相比),而且我不相信这些示例的工作方式相同。

我正在寻找的内容非常简单:

  • 会有一些单独的任务——为了便于讨论,我们称之为integrationTest
  • 当我调用 gradle test 时,integrationTest 任务将运行。
  • integrationTest 任务在我调用 gradle integrationTest 时运行(在 test 任务之后)。
  • 当我调用 gradle check 时,integrationTest 任务运行(在 test 任务之后)。
  • integrationTest 任务将具有与 test 任务相同的依赖项和类路径配置。
  • integrationTest 任务将使用与test 任务相同的源路径(即src/test/java),但只会运行以*IT 结尾的测试(只是为了简化本次讨论的default Failsafe inclusion pattern)。
  • test 任务将忽略所有以 *IT 结尾的测试。

这实际上是一个非常简单的用例。 (我只是详细介绍了,所以不会有歧义。)我可以turn that on in Failsafe 用两行表示目标,用三行表示依赖。由于 Gradle 将 XML 冗长排除在等式之外,我应该能够在两行中进行配置,对吧?

明确一点,我不想在 Gradle 中使用 Maven Failsafe。我只是想将 Gradle 配置为与默认的 Failsafe 配置类似的行为方式,正如我在上面详述的那样。

【问题讨论】:

    标签: java maven gradle integration-testing


    【解决方案1】:

    尤其是用于集成测试的 Gradle 文档——但它们看起来相当复杂(与 Maven Failsafe 相比)

    您正在将插件(Maven Failsafe)与标准/香草 Gradle 配置进行比较。插件抽象出所有底层细节,因此比较两者是不公平的。如果您查看 Maven Failsafe 的 source,您会发现它与 Gradle 相比同样“复杂”。

    (...) 而且我认为这些示例的工作方式不同。

    为典型应用程序配置集成测试的文档。但是,由于您有特定的需求,因此您需要适应它们。

    由于 Gradle 将 XML 冗长性排除在外,我应该能够在两行中进行配置,对吧?

    不,因为您再次将插件与标准/香草 Gradle 配置进行比较。 XML 与 Groovy/Kotlin DSL 的好坏有待商榷,这是一个见仁见智的问题。

    对于您的要求,我相信我已经在下面捕获了它们(未经测试):

    sourceSets {
        create("integrationTest") {
            compileClasspath += sourceSets.test.get().output
            runtimeClasspath += sourceSets.test.get().output
        }
    }
    
    val integrationTestImplementation by configurations.getting {
        extendsFrom(configurations.testImplementation.get())
    }
    
    configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())
    
    val integrationTest by tasks.registering(Test::class) {
        description = "Runs integration tests."
        group = "verification"
        testClassesDirs = sourceSets["integrationTest"].output.classesDirs
        classpath = sourceSets["integrationTest"].runtimeClasspath
        filter {
            includeTestsMatching("IT*")
            includeTestsMatching("*IT")
            includeTestsMatching("*ITCase")
        }
        shouldRunAfter("test")
    }
    
    tasks {
        test {
            filter {
                excludeTestsMatching("IT*")
                excludeTestsMatching("*IT")
                excludeTestsMatching("*ITCase")
            }
        }
        register("integrationTest", Test::class) {
            description = "Runs integration tests."
            group = "verification"
            testClassesDirs = sourceSets["integrationTest"].output.classesDirs
            classpath = sourceSets["integrationTest"].runtimeClasspath
            filter {
                includeTestsMatching("IT*")
                includeTestsMatching("*IT")
                includeTestsMatching("*ITCase")
            }
            shouldRunAfter(test)
        }
    }
    

    虽然这有点冗长/尴尬,因为您希望集成测试与测试位于同一源集中。所以上面可以简化为:

    tasks {
        test {
            filter {
                excludeTestsMatching("IT*")
                excludeTestsMatching("*IT")
                excludeTestsMatching("*ITCase")
            }
        }
        register("integrationTest", Test::class) {
            description = "Runs integration tests."
            group = "verification"
            testClassesDirs = sourceSets.test.get().output.classesDirs
            classpath = sourceSets.test.get().runtimeClasspath
            filter {
                includeTestsMatching("IT*")
                includeTestsMatching("*IT")
                includeTestsMatching("*ITCase")
            }
            shouldRunAfter(test)
        }
    }
    

    【讨论】:

    • 这看起来很有希望,谢谢!如果可行,我将分配赏金以表达我的感激之情。 1. 能否详细谈谈register("integrationTest", Test::class) 与官方文档推荐的task integrationTest(type: Test) 有何不同? 2. 使用shouldRunAfter(test) 是否会保证失败的测试会在check 任务结束之前使构建失败,或者Gradle 是否会在之后 check 安排集成测试? (文档建议添加check.dependsOn integrationTest)。 3. verification 是其他任务使用的官方记录组吗?
    • (1) 我使用 Kotlin DSL 而不是 Groovy DSL,因此语法不同。通常,您应该支持任务配置避免 API(惰性 API)。 (2) 否,如果您想因任何测试失败而立即使构建失败,请将failFast 属性设置为true。不要将文档作为唯一的解决方案,将其用作参考并根据您的需要进行定制。有关dependsOnshouldRunAfter 的详细信息,请参阅DefaultTask 的javadocs。 (3) Group 是一个任意的字符串值,尽管插件作者通常会重用现有的组。 LifecycleBasePlugin 定义验证。组。
    • 就我而言,我别无选择,只能使用 Groovy DSL。我仍然不完全清楚register("integrationTest", Test::class) 的工作原理以及它是否等同于task integrationTest(type: Test)。您是否有机会澄清这一点,甚至可能展示 Groovy DSL 的一部分?
    • 啊,看起来 Gradle 在你提到的这个“避免配置”的事情上有一个article。我会去阅读它,看看它是否回答了我的问题。
    • 这如何转化为 Groovy 我需要一段时间才能弄清楚。问题的重点是如何以简单的方式进行配置,但看起来我仍然需要研究在哪里设置failFast,在哪里调用Groovy 中的register() 等等。所以它仍然不简单.我会继续研究,但我希望能在 Groovy 中看到完整的答案。
    最近更新 更多