Aggregating test reports in a project not working

I am unable to aggregate test reports.

In my java/scala projects, I have declared:

test {
  // Disable the test report for the individual test task (for aggregation)
  reports.html.enabled = false

And in my root project (which does not declare any plugins, this is a polyglot project):

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

But this produces an error at the root project “reportOn” line:

  * What went wrong:  A problem occurred evaluating root project 'x'.  > Could not find property 'test' on project ':x-proj1'.  

Funnily enough, x-proj1 is actually a java/scala project that does declare a test task, so the error message doesn’t even make sense to me. It seems the root build is being evaluated before the subproject builds are, so the test task does not yet exist.

(Gradle 1.11)

Regards, Raman

Still the same issue on 1.12.

Gradle evaluates projects in alphanumeric order by default, so your ‘x-proj1’ project has not been evaulated when the root project is evaluated and hence does not have any tasks defined at that time.

You could try using ‘evaluationDependsOnChildren()’ in your root project to ensure all the subprojects are evaluated first.

For more on how the gradle evaluation phase works take a look at chapter 55 of the user manual.

Unfortunately, I cannot use evaluationDependsOnChildren() because the root project declares a bunch of stuff used by subprojects e.g. various ext. properties. I have tried moving these to a subprojects section but that doesn’t seem to work either, probably because that isn’t being evaluated before the subprojects.

Even if I could get it working, doing test report aggregation shouldn’t require totally reorganizing my project right?

evaluationDependsOnChildren() was just something to try. The important thing is to understand how evaluation order affects things and then hopefully you can figure out something that will work on your project from the available mechanisms.

For example, you could try this

task testReport(type: TestReport) {
  destinationDir = file("$buildDir/reports/allTests")
  subprojects {
    afterEvaluate { subproject ->
        testReport.reportOn subproject.test

Perryn, that suggestion worked, thank you.

I read through Chapter 55 and am still confused as to why, however. The first reference to the word “Evaluation” is section 55.6.1 which explains about receiving notifications when a project evaluation is done, but never explains what it is actually doing.

Why would Gradle be trying to run a task of type TestReport before every project has even been evaluated? Shouldn’t it automatically defer TestReport until after (or during) the execution build phase?

I have to admit, Gradle’s multi-project build syntax/requirements are extremely confusing to me. It works well once you figure out what needs to be done, but getting there requires a lot of experimentation.

Thinking about it some more, I think I understand it – “reportOn” method is just configuring the testReport task with the test object of the subproject. Which won’t exist until after the evaluation of the subproject.

Yep thats right.

During the configuration phase, gradle evaluates each project to find out what tasks it has, and to configure those tasks. None of the tasks are actually run until the execution phase.

So what we did with the solution was to add some more configuration that will happen during the configuration phase, but after project evaluation.

It all makes perfect sense once you understand it, but you are right it can be quite unintuitive at first. It is something we are working on improving.

Thank you for your help!