当所有测试均为最新时,如何运行Gradle测试?


130

我已经设置了成绩脚本。当我执行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构建当然会工作……我只希望能够重置测试,而不是重新构建整个项目:我该怎么做?


3
根据给定的信息,这似乎是不必要的。如果应用程序代码和测试代码均未更改,那么为什么需要重新运行测试?
2015年

10
@Jolta我代码中的某些测试与三方输入有关,我正在运行测试,不仅要确保我没有在代码内放入任何错误,还要检查三方输入是否有所更改我得到的消息
USer22999299 2015年

4
不好意思,但是我真的不认为这是正确的思考方式:如果您拥有可变的3方输入,不是以某种方式模拟这些输入的正确方式吗?测试实际上应该是关于测试所编写的代码。如果您依靠三方输入来接受是不可接受的,那么您不是很明显会得到假阳性的危险吗?策略不应该在您的应用程序代码中迎合问题输入吗?
麦克啮齿动物

9
@mikerodent考虑使用第三方在线服务测试您的代码。您可能希望监视服务API中的可能更改,以便能够尽快响应已部署的修补程序。CI测试不是这样做的好方法吗?使用模拟只会告诉您您自己的代码没有回归,但是依赖项仍然可能有变化。使用真实服务将表明您的产品可以在当前环境中实际执行预期的操作。
Elist

5
从集成测试的角度来看,这也是有效的,在这种情况下,测试的目的是验证您的代码与其他代码段的集成,在这种情况下,不宜在依赖关系上进行模拟
1800信息

Answers:


171

一种选择是--rerun-tasks命令行中使用该标志。这将重新运行所有测试任务及其依赖的所有任务。

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

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

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

因此,要重新运行测试,您需要做的就是还运行cleanTest任务,即:
gradle cleanTest test


3
gradle cleanTest test不会重新运行测试,它会清除其输出,但是test任务仍将从缓存中获取测试结果-参见github.com/gradle/gradle/issues/9153
dan.m是user2321368

3
上面的评论是正确的。但是,如果您使用--no-build-cache,则它将按预期运行,例如gradle cleanTest test --no-build-cache
vRallev

51

另一种选择是在build.gradle中添加以下内容:

test.outputs.upToDateWhen {false}

1
我将这种技术用于funcTest我创建的运行功能测试的任务。
pharsicle

4
这是比接受的答案更好的方法,因为它将仅应用于所需的任务。将upToDateWhen可以在任何“代码驱动”的方式使用,如系统属性,环境变量,项目性质等
mkobit

1
正如答案stackoverflow.com/a/52484259/340175所提到的,有一个有用的博客文章blog.gradle.org/stop-rerunning-tests,它解释了为什么不建议将此方法用作一般方法。但是,我同意这可能有用,并且确实可以解决问题。
朱利安·哈蒂

是的,这是一个过时的答案,当我编写此Gradle的版本为2.11时,才开始可用,但仍然有许多粗糙的边缘,今天这些边缘已经打磨过了。
弗朗哈特曼

1
好答案!!!使用参数传递了它gradle test -Prerun-tests。build.gradle中的代码:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka,


17

最近,这是Gradle博客文章停止重新运行测试中的主题。在笔者给出了一个例子使用outputs.upToDateWhen { false },并解释为什么它是错误的:

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

该摘录的作者可能想说的是“始终重新运行我的测试”。这不是此代码片段的功能。它只会将任务标记为过期,从而迫使Gradle 重新创建输出。但是,如果启用了构建缓存,则Gradle不需要运行任务来重新创建输出。它将在缓存中找到一个条目,并将结果解压缩到测试的输出目录中。

此代码段也是如此:

test.dependsOn cleanTest

清除输出后,Gradle将从构建缓存中解压缩测试结果,因此不会重新运行任何内容。简而言之,这些片段造成了非常昂贵的无操作。

如果您现在正在考虑“好的,我也将停用缓存”,那么让我告诉您为什么不应该这样做。

然后,作者继续说明为什么重新运行某些测试会浪费时间:

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

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

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

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

我建议阅读整个博客文章。


8
对于您正在谈论的特定用例,这听起来很棒,但是我正在针对实时的外部Web服务编写部署后测试,并且碰巧正在使用junit和gradle来完成此操作。被测代码并不住在回购,而事实上没有“申请代码”,因为实际上我测试现场制作系统,而不是代码本身。感谢您的回答,这非常有用!只是想指出,还有其他用例确实需要每次都重新运行测试,即使gradle所知道的代码都没有改变
布兰登

11

如果您不想修改命令行,以下是使用“ 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

1
在运行cleanTest之前test不会重新运行测试,它会清除其输出,但是测试任务仍将从缓存中获取测试结果-参见github.com/gradle/gradle/issues/9153
dan.m是user2321368 '19

8

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

cleanTest 由于构建缓存的原因,其本身可能不足。

因此,完成此操作的最佳方法是:

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

0

另外,必须添加--rerun-tasks确实是多余的。永远不会发生。创建一个--no-rerun-tasks并在以下--rerun-tasks情况下设为默认值cleanTask



-4

我认为这是一个有效的问题,因为在Gradle中有可能运行此命令test,而实际上什么也没发生!

但是我会质疑是否有必要这样做,就像Jolta在他的评论中说的那样:如果没有代码更改,为什么需要重新测试?如果您对第三方输入有疑问,我想说您需要在您的应用代码中满足此要求。如果您担心自己的代码可能“不稳定”,即能够一次通过所有测试,但一次又一次(或第100次)不能通过所有测试,那么您是否无需考虑为什么有这些疑问并加以解决?

我个人认为这是Gradle中的一个(非常小的)设计错误:如果一切都完全是最新的,而不是“成功构建”,它应该说“自从上一次成功构建以来没有改变:没有完成”。


3
“您不需要思考为什么有这些疑问,并解决它们吗?”:是的,但是为了获得可考虑的数据,我想运行几次测试,看看会发生什么。那太疯狂了吗?
mhsmith

1
@mikerodent我部分同意您的观点。在“简单”的情况下,通常是简单的白盒单元测试,其中无需更改代码就意味着无需进行任何真正的重新测试。考虑一下具有依赖性的测试。“哦,是的,Docker没有运行,等等。” 在测试中,是由基础结构(以及在开发人员中)设置依赖关系(它们是“提供”的)而非构建的。在这些情况下,我总是希望能够重新运行。
dbalakirev

@dbalakirev是的,这发生在我身上...但是您不应该能够模拟这些依赖项的角色,例如Docker ...吗?我的意思是,如果您这样做,那么您不是要存储将来的问题吗?我并不是说我有100%的把握,但是我想说的是,在无疑比我们的测试更理想的世界中,您的测试应该涵盖所有基础。
麦克啮齿动物

您可以嘲笑“是”,因为它有一个依赖项(docker),如果您失败,则意味着即使代码未更改也要重新运行。我想强调一下这种想法不是针对单元测试或1.您试图避免依赖关系的测试2.或至少使用测试框架模拟它们,而是如果愿意的话,它们是在真正“提供”的时候。
-dbalakirev

2
__如果没有代码更改,为什么需要重新测试?__您是否听说过集成测试?
Bogdan Mart
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.