How do you generate a test report for a multi-project build when some projects do not have a test block?

On stackoverflow it was suggested that a test report for a multi-project build can be aggregated with the following code:

ubprojects {
    apply plugin: 'java'
      // Disable the test report for the individual test task
    test {
        testReport = false
    }
}
  task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    // Include the results from the 'test' task in all subprojects
    reportOn subprojects*.test
}

However, if I have a non-flat project hierarchy that includes some parent projects, this will fail because not all projects have a ‘test’ task. How can I generate an aggregated test report that will exclude the subprojects that do not have a test task?

Hi Kevin,

You could either use

plugins.withId("java") {
    // java is guaranteed to be applied now so disabling testReport will work
}

Or you could use the TaskContainer:

tasks.withType(Test) {
  // perform additional configuration on tasks of type Test
}

You can also use the TaskContainer to select tasks for ‘reportOn’.

Sterling,

I’m not sure how this would work for the testReport task. I need a way to set the reportOn property which fails if I set it to subprojects*.test when there are one or more projects which do not have a test task.

Other ideas?

I was thinking:

task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    // Include the results from the 'test' task in all subprojects
    reportOn subprojects*.tasks.withType(Test)
}

That’ll aggregate all of your Test tasks, which you may not want if you have other Test types (e.g., integTest). You could then use…

reportOn subprojects*.tasks.matching { it.name == "test" }

I didn’t try this, but I think reportOn will recursively convert the list to a flattened list of Test tasks. The return type of subproject*.tasks.withType(Test) is basically a list of lists of Tests

It seems like whenever I use the spread operator as you suggest it returns the following error:

No signature of method: java.util.ArrayList.withType() is applicable for argument types: (java.lang.Class) values: [class org.gradle.api.tasks.testing.Test]

Possible solutions: asType(java.lang.Class), asType(java.lang.Class), with(groovy.lang.Closure)

It seems like the spread operator converts the Set to an ArrayList. Keep in mind that the list of subprojects is interleaved with projects that have the test Task and projects which don’t.

I was able to do what you recommended with the following syntax instead:

reportOn subprojects.findAll { it.hasProperty(‘test’) }*.test

Not as elegant as your solution. Perhaps I’m doing something wrong.

The other thing I can think of…

reportOn subprojects.collect { it.tasks.withType(Test) }