Can I produce a single aggregated report for all of my tests, while supporting up-to-date checking?

OK now it makes sense! The reason that you’re seeing this behaviour is because you effectively have 2 projects generating test reports into the same directory: the ‘root’ project and the ‘:one’ subproject.

Ignoring the fact that maybe gradle shouldn’t generate a test report for the root project that has no tests, it makes sense that the ‘:one:test’ task checks if it’s outputs have changed, and re-executes if they have. Although in this case this could be fixed by using ‘subprojects’ instead of ‘allprojects’, you’re likely to have multiple subprojects in a real multiproject build, so this isn’t really a solution.

So until gradle supports this sort of test aggregation in the wild, you’ll need to code up a task to do this yourself.

We have something that does this in the gradle build:

task aggregateTestReports(type: TestReportAggregator) {
    testReportDir = file("${reportsDir}/tests")
    testResultsDir = file("${buildDir}/test-results")
    projects = subprojects
}
  class TestReportAggregator extends Copy {
    def projects
      File testResultsDir
      @OutputDirectory
    File testReportDir
      def TestReportAggregator() {
        dependsOn { testTasks }
        from { inputTestResultDirs }
        into { testResultsDir }
    }
      @TaskAction
    def aggregate() {
        def report = new org.gradle.api.internal.tasks.testing.junit.report.DefaultTestReport(testReportDir: testReportDir, testResultsDir: testResultsDir)
        report.generateReport()
    }
      def getTestTasks() {
        projects.collect { it.tasks.withType(Test) }.flatten()
    }
      def getInputTestResultDirs() {
        testTasks*.testResultsDir
    }
}

Note that this example uses an internal class ‘DefaultTestReport’, so the api may change in the future.