【问题标题】:How to run Gradle test when all tests are UP-TO-DATE?当所有测试都是最新的时如何运行 Gradle 测试?
【发布时间】:2015-06-08 05:43:30
【问题描述】:

我设置了成绩脚本。 当我执行 Gradle 构建时,一切正常,它运行 jUnit 测试。

之后,当我运行 Gradle 测试时,我得到以下信息:

C:\Users\..\..\Project>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE

当我执行gradle clean 时,Gradle 构建当然可以工作...... 我希望能够只重置测试,而不是构建整个项目:我应该怎么做?

【问题讨论】:

  • 根据给定的信息,这似乎是不必要的。如果应用程序代码和测试代码都没有改变,为什么需要重新运行测试?
  • @Jolta 我的代码中的一些测试与 3 方输入相关,我运行测试不仅是为了确保我没有在代码中添加任何错误,还检查是否我得到的 3 方输入发生了一些变化
  • 对不起,我很挑剔,但我真的不认为这是思考这个问题的正确方法:如果你有可变的 3 方输入不是处理这个问题的正确方法以某种方式模拟这些输入?测试实际上应该是关于测试你正在编写的代码。如果您依赖 3 方输入是不可接受的,那么您是否会面临相当明显的误报危险?该策略不应该将问题输入作为应用代码的一部分吗?
  • @mikerodent 考虑针对第 3 方在线服务测试您的代码。您可能希望监控服务 API 中可能发生的变化,以便能够尽快对已部署的修复做出响应。 CI 测试不是这样做的好方法吗?使用模拟只会告诉您自己的代码没有回归,但依赖项仍然可能会发生变化。使用真实的服务,说明你的产品在当前环境下确实可以执行预期的操作。
  • 从集成测试的角度来看,这也是有效的,其中测试的目的是验证您的代码与其他代码位的集成,在这种情况下不适合模拟依赖项

标签: java gradle build.gradle


【解决方案1】:

一种选择是在Forcing tasks to execute 部分中使用--rerun-tasks 标志。这将重新运行所有测试任务及其依赖的所有任务。

如果您只对重新运行测试感兴趣,那么另一种选择是在执行测试之前让 gradle 清理测试结果。这可以使用cleanTest 任务来完成。

一些背景知识 - Java 插件为每个其他任务定义了一个干净的任务。根据Tasks 文档:

cleanTaskName - 删除指定任务创建的文件。 cleanJar 会删除 jar 任务创建的 JAR 文件,cleanTest 会删除 test 任务创建的测试结果。

因此,为了重新运行测试,您只需要运行cleanTest 任务,即:
gradle cleanTest test

【讨论】:

  • gradle cleanTest test 不会重新运行测试,它会清理它们的输出,但test 任务仍会从缓存中获取测试结果 - 请参阅github.com/gradle/gradle/issues/9153
  • 上面的评论是对的。但是如果你使用--no-build-cache,那么它将按预期工作,例如gradle cleanTest test --no-build-cache.
  • --rerun-tasks 只是门票。 --no-build-cache 即使清洁对我来说也不起作用。谢谢@Amnon
  • gradle cleanTest test 为我工作。
【解决方案2】:

其他选项是在 build.gradle 中添加以下内容:

test.outputs.upToDateWhen {false}

【讨论】:

  • 我将这种技术用于我创建的用于运行功能测试的funcTest 任务。
  • 这是一种比接受的答案更好的方法,因为它只会应用于所需的任务。 upToDateWhen 可以以任何“代码驱动”的方式使用,例如系统属性、环境变量、项目属性等。
  • 正如答案stackoverflow.com/a/52484259/340175 提到的,有一篇有用的博客文章blog.gradle.org/stop-rerunning-tests 解释了为什么不建议将此方法作为一般方法。不过,我同意它可能有用并且可以满足问题的要求。
  • 是的,这是过时的答案,当我写这个 Gradle 时,它​​是 2.11 版本,刚刚开始可用,但仍然有很多粗糙的边缘,今天已经打磨了。
  • 很好的答案!!!使用参数传递它:gradle test -Prerun-tests。 build.gradle 中的代码:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
【解决方案3】:

gradle test --rerun-tasks

指定忽略任何任务优化。

来源:https://gradle.org/docs/current/userguide/gradle_command_line.html

【讨论】:

  • 我认为它也会重新运行所有相关任务,这不是询问者的预期行为。
【解决方案4】:

这是最近 Gradle 的博文 Stop rerunning your tests 上的主题。 author 显示了一个使用 outputs.upToDateWhen { false } 的示例并解释了错误的原因:

这实际上并不强制重新运行

这个 sn-p 的作者可能想说的是“总是重新运行我的测试”。这不是这个 sn-p 所做的。它只会将任务标记为过期,强制 Gradle 重新创建输出。但事情是这样的,如果启用了构建缓存,Gradle 不需要运行任务来重新创建输出。它会在缓存中找到一个条目并将结果解压到测试的输出目录中。

这个sn-p也是如此:

test.dependsOn cleanTest

Gradle 将在清理输出后从构建缓存中解压测试结果,因此不会重新运行任何内容。简而言之,这些 sn-ps 正在创建一个非常昂贵的空操作。

如果你现在想“好吧,我也会停用缓存”,让我告诉你为什么不应该这样做。

然后,作者继续解释为什么重新运行一些测试是浪费时间:

您的绝大多数测试应该是确定性的,即给定相同的输入,它们应该产生相同的结果。

在少数情况下,您确实希望在代码未更改的情况下重新运行测试,您应该将它们建模为输入。以下是博客文章中的两个示例,它们显示了添加输入以便任务在其最新检查期间使用它。

task randomizedTest(type: Test) {
  systemProperty "random.testing.seed", new Random().nextInt()
}

task systemIntegrationTest(type: Test) {
  inputs.property "integration.date", LocalDate.now()
}

我建议阅读整篇博文。

【讨论】:

  • 这对于您正在谈论的特定用例来说听起来很棒,但我正在针对实时外部 Web 服务编写部署后测试,并且恰好使用 junit 和 gradle 来完成此操作。被测代码并不存在于 repo 中,实际上 is 没有“应用程序代码”,因为我实际上是在测试实时生产系统而不是代码本身。感谢您的回答,这非常有用!只是想指出,即使没有任何代码 gradle 知道正在发生变化,也有其他用例需要每次都重新运行测试
  • 作者缺少测试的基本概念:非确定性行为。如果您怀疑测试是可以的,但代码有一些错误并且导致结果不确定,那么,如果您在第一次运行时碰巧成功,那么根据这个短浅的建议,您将永远不会获得堆栈跟踪。测试应该运行你想要的次数。考虑到运行多个测试的不良做法是完全错误的,并且违背了测试概念。
【解决方案5】:

--rerun-tasks 有效,但效率低,因为它会重新运行所有任务。

cleanTest 本身可能不够,因为构建缓存。

所以,最好的方法是:

./gradlew --no-build-cache cleanTest test

【讨论】:

    【解决方案6】:

    这是使用“build.gradle”文件的解决方案,以防您不想修改命令行:

    test {
        dependsOn 'cleanTest'
        //Your previous task details (if any)
    }
    

    这是输出。请注意与您之前的输出相比的 2 处更改:

    1) 一个新的“cleanTest”任务出现在输出中。

    2) 'test' 总是被清理(即从不'UP-TO-DATE')所以它每次都会被执行:

    $ gradle build
    :compileJava UP-TO-DATE
    :processResources UP-TO-DATE
    :classes UP-TO-DATE
    :findMainClass
    :jar
    :bootRepackage
    :assemble
    :cleanTest
    :compileTestJava UP-TO-DATE
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :test
    :check
    :build
    

    【讨论】:

    • test 之前运行cleanTest 不会重新运行测试,它会清理它们的输出,但测试任务仍会从缓存中获取测试结果 - 请参阅 github.com/gradle/gradle/问题/9153
    【解决方案7】:

    另外, 必须添加--rerun-tasks 真的是多余的。永远不会发生。创建--no-rerun-tasks 并在cleanTask 时将--rerun-tasks 设为默认

    【讨论】:

      【解决方案8】:

      TL;DR

      test.dependsOn cleanTest
      

      【讨论】:

      【解决方案9】:

      以上方法都不适合我。
      对我有用的只是从 /Users/<username>/.gradle/caches/build-cache-1/ 的缓存目录中删除所有项目。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-19
        • 1970-01-01
        • 1970-01-01
        • 2018-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-04
        相关资源
        最近更新 更多