Gradle `tasks.withType()` 之后添加的任务的奇怪行为

标签 gradle build.gradle

我正在使用 Gradle 2.14.1 和 https://github.com/unbroken-dome/gradle-testsets-plugin添加集成测试任务。我想配置 HTML 报告的位置。 默认任务使用:

<project>/build/reports/tests

测试集插件配置:

<project>/build/intTest

对于 intTest 任务,我想要:

<project>/build/reports/test
<project>/build/reports/intTest

这是我的配置:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
    }
}

apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'

defaultTasks = ['clean', 'build']

tasks.withType(Test) {
    reports.html.destination = new File(project.reportsDir, name)

    println(it.name + '\t' + reports.html.destination)
}

task wrapper(type: Wrapper) {
    description = 'Defines the common gradle distribution for this project.'
    gradleVersion = '2.14.1'
}

testSets {
    intTest
}

intTest.dependsOn test
check.dependsOn intTest

repositories {
    jcenter()
}

dependencies {
    testCompile 'junit:junit:4.12'
    intTestCompile 'junit:junit:4.12'
}

println('===== final config =====')
println(test.name + '\t' + test.reports.html.destination)
println(intTest.name + '\t' + intTest.reports.html.destination)

(请暂时忽略println语句。)

完整构建后,intTest 任务的报告位于错误的位置(默认),并且应用了标准 test 任务的配置:

$ ls build/
classes  dependency-cache  intTest  intTest-results  libs  reports  test-results  tmp

$ ls build/reports/
test

我添加了一些输出来查看发生了什么,这看起来很奇怪(项目的根目录是“blob”):

test    /home/wujek/blob/build/reports/test
intTest /home/wujek/blob/build/reports/intTest
===== final config =====
test    /home/wujek/blob/build/reports/test
intTest /home/wujek/blob/build/intTest

因此,在 tasks.withType() block 中,报告的位置是正确的,但最终并非如此。

请注意,将 tasks.withType() block 移到 testSets block 之后适用于该项目,但我的实际设置是模式复杂的:我有多个模块,根 build.gradle 使用 subprojects block 和 tasks.withType() block 来配置所有模块的报告位置,然后其中一个子模块添加了一个新的测试集,并且其测试任务的 HTML 报告的位置错误。为了解决这个问题,我必须在添加测试集的子模块中重复配置。

这是怎么回事?为什么 tasks.withType() block 说配置有效,但实际上却不起作用?

最佳答案

这是由于 Gradle 中排序配置的特殊性造成的。让我们浏览一下您的代码,Gradle 会对其进行处理,看看会发生什么(跳过不相关的行):

apply plugin: 'org.unbroken-dome.test-sets'

这会执行测试集插件的 apply 方法,其中包括 the creation of a class which listens for test sets to be addedIt adds a whenObjectAdded actiontestSets 容器。您尚未添加任何测试集,因此让我们返回到您的 build.gradle

tasks.withType(Test) {
    reports.html.destination = new File(project.reportsDir, name)

    println(it.name + '\t' + reports.html.destination)
}

您现在已经添加了一个操作,该操作将应用于所有现有的测试任务以及创建的新任务。现在一切都展开了:

testSets {
    intTest
}

这将创建一个名为 intTesttestSet。测试集插件中的 whenObjectAdded 操作现在触发:

  1. intTest 设置测试任务 is created .
  2. 您的 withType 操作会触发,因为现在有一个新的 Test 任务。这会将报告设置为您想要的位置。
  3. whenObjectAdded 操作现在继续,到达 this line它还设置 html 报告位置,覆盖您刚刚设置的内容。

当您更改此设置以首先声明 testSet 时,它会:

  1. whenObjectAdded - 创建测试任务
  2. whenObjectAdded - 设置测试任务的 HTML 报告位置
  3. withType 由您注册
  4. withType 触发将 HTML 报告位置设置为您所需的目标

没有硬性规则可以避免这种情况,因为插件可以并且确实采用截然不同的方法来注册其配置操作。一般来说,我尝试按以下顺序分解 build.gradle:

  1. Buildscript block (如果需要)
  2. 应用插件
  3. 设置项目级别属性(组、版本、源兼容性等)
  4. 配置扩展(源集、测试集、配置、依赖项)
  5. 配置任务(直接或 withType)

通常这有助于允许触发配置的插件在我的配置进行更改之前注册默认值。

仅供引用,Gradle's new, and still incubating, model space旨在帮助解决此配置排序问题。它并不完美,但可以让顺序更加明确。

关于Gradle `tasks.withType()` 之后添加的任务的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38621330/

相关文章:

java - 如何针对多个版本的依赖项运行单元测试

java - 如何在Gradle 5.x中使用自定义插件排除已解决的插件?

android - 如何解决java.util.zip.ZipException duplicate entry : com/google/gson/annotations/Expose.类?

java - 如何设置 gradle distZip 任务以将资源正确放入子目录和类路径中?

eclipse - 使用AspectJ配置进行Eclipse Gradle导入

gradle - 为什么 gradle-clojure 插件会跳过 compileClojure 任务?

Android Studio (3.2.1) Instant Run 不适用于 Jacoco 0.8.2?

java - 在 Gradle 中使用 DBDeploy 并使用 hibernate 作为 ORM

android - 更新Android Studio后,Android资源编译失败

android - 使用 tasks.getByName 找不到名称的任务