Gradle Release Notes

We are excited to announce Gradle 9.3.0-20251127013807+0000 (released 2025-11-27).

This release brings a set of testing improvements, including a more detailed HTML test report for nested, parameterized, and suite-based tests, better aggregate reporting, and a new streaming API in TestKit for efficiently reading build output.

It also enhances build authoring with a new AttributeContainer.named() convenience method for more concise attribute configuration.

Finally, there are error and warning reporting improvements, with Problems API reports now rendered in the console when using --warning-mode=all.

We would like to thank the following community members for their contributions to this release of Gradle: Adam, Adam, Aharnish Solanki, Andrzej Zabost, Björn Kautler, Boris Petrov, Jendrik Johannes, Kamil Krzywanski, KANAKALA SAI KIRAN, Megmeehey, NurmukhametovAlexey, Philip Wedemann, Piotr Kubowicz, Samay Kumar, Shin Minjun, Stefan Oehme, Vincent Potuček, Yongshun Ye.

Be sure to check out the public roadmap for insight into what's planned for future releases.

Table Of Contents

Upgrade instructions

Switch your build to use Gradle 9.3.0-20251127013807+0000 by updating the wrapper in your project:

./gradlew wrapper --gradle-version=9.3.0-20251127013807+0000 && ./gradlew wrapper

See the Gradle 9.x upgrade guide to learn about deprecations, breaking changes, and other considerations when upgrading to Gradle 9.3.0-20251127013807+0000.

For Java, Groovy, Kotlin, and Android compatibility, see the full compatibility notes.

New features and usability improvements

Testing improvements

Gradle provides APIs for testing build logic and plugins with TestKit, and a dedicated Test task for JVM code.

Testing refactoring

The HTML Test Report generated by the test task, TestReport, and other AbstractTestTask users now provides a more detailed view of the test results. This is due to a refactoring of the testing infrastructure to use the incubating TestEventReporter API internally. Additionally, the binary output has been adjusted to better support non-class-based testing frameworks.

In the following sections:

Nested test changes

For JUnit 4 and JUnit Jupiter, nested test classes are now shown nested under their enclosing class in the HTML Test Report.

For example, if you had an OuterClass with an InnerClass nested inside it, it would previously be shown as:

+ OuterClass$InnerClass
|-- someTestMethodInInnerClass

It will now be reported in the HTML Test Report as:

+ OuterClass
|-+ InnerClass (or OuterClass$InnerClass for JUnit 4)
  |-- someTestMethodInInnerClass

With multiple inner classes:

+ OuterClass
|-+ InnerClass1 (or OuterClass$InnerClass1 for JUnit 4)
  |-- someTestMethodInInnerClass1
  + InnerClass2 (or OuterClass$InnerClass2 for JUnit 4)
  |-- someTestMethodInInnerClass2

The XML report remains the same, nested classes are still written as TEST-OuterClass$InnerClass.xml.

Parameterized test changes

Parameterized tests now create a suite that contains all the parameterized test cases for a given method.

For example, if you had a class TestClass with two parameterized paramTest1/2 methods, it would previously be shown as:

+ TestClass
|-- paramTest1[0]
|-- paramTest1[1]
|-- paramTest1[2]
|-- paramTest2[a]
|-- paramTest2[b]
|-- paramTest2[c]

It will now be reported in the HTML Test Report as:

+ TestClass
|-+ paramTest1
  |-- paramTest1[0]
  |-- paramTest1[1]
  |-- paramTest1[2]
|-+ paramTest2
  |-- paramTest2[a]
  |-- paramTest2[b]
  |-- paramTest2[c]
Suite changes

Suites now contain the classes they run, rather than those classes being shown as siblings.

For example, if you had a suite AllTests that ran TestClass1 and TestClass2, it would previously be shown as:

+ AllTests
+ TestClass1
|-- someTestMethodInClass1
+ TestClass2
|-- someTestMethodInClass2

It will now be reported in the HTML Test Report as:

+ AllTests
|-+ TestClass1
  |-- someTestMethodInClass1
|-+ TestClass2
  |-- someTestMethodInClass2

In the XML report, only the class report is emitted (TEST-SomeTestClass.xml).

Package suite changes

Packages are no longer represented as containers in the report.

There are two main reasons:

  1. With support for non-class-based testing, Gradle cannot reliably determine if a container corresponds to a class, so synthesizing a package container can be misleading.
  2. This behavior now aligns more closely with how testing frameworks and IDEs group tests.
Test standard output/error changes

Standard output and standard error (collectively, "output") are no longer combined from individual tests to the container/class level. This makes it easier to locate output that is relevant to a specific test.

Before and after class output is now associated with the correct class in JUnit 4, JUnit Jupiter, and TestNG (starting with TestNG 6.9.13.3). Before and after suite or container output is now associated with the correct suite or container for JUnit 4 (starting with JUnit 4.13), JUnit Jupiter, and TestNG (starting with TestNG 6.19.13.3).

Aggregate report changes

The aggregate report generated by the Test Report Aggregation Plugin or manually with TestReport now supports overlapping test structures.

For example, when a suite with the same name exists in multiple subprojects, each individual report source is represented as a "root".

You can switch between roots in the aggregate HTML Test Report: new-aggregate-report.png

As a result, not all children are listed on the first tab anymore. To see the tests from a specific source, select its corresponding root tab.

Stream TestKit output

Gradle TestKit's BuildResult now offers a new method for accessing the build console output efficiently, especially for builds that produce a large volume of logs.

BuildResult.getOutput() returns a String with the full build console output. This can use large amounts of memory for builds with extensive logs.

A new BuildResult.getOutputReader() method is available, returning a BufferedReader for streaming the build output incrementally. This can help reduce memory pressure in TestKit tests.

Ensure you close the BufferedReader after use. We recommend the standard Java try-with-resources pattern for this:

void testProject() {
    BuildResult buildResult = GradleRunner.create()
        .withProjectDir(File("test-project"))
        .withArguments(":build", "--info")
        .build();

    try (BufferedReader outputReader = buildResult.getOutputReader()) {
        List<String> logLines = outputReader.lines()
            .filter(line -> line.contains("example build message"))
            .collect(Collectors.toList());
        // do something with the log lines...
    }
}

Build authoring improvements

Gradle provides rich APIs for plugin authors and build engineers to develop custom build logic.

New AttributeContainer.named() method

This release introduces a new convenience method on AttributeContainer, named(), which can create attribute values directly from the container without requiring a separate ObjectFactory instance.

This method makes attribute assignment more concise while preserving the same semantics as creating a named value via ObjectFactory:

configurations.resolvable("foo") {
    attributes {
        // Before: 
        attribute(Usage.USAGE_ATTRIBUTE, objects.named("red"))
        
        // After:
        attribute(Usage.USAGE_ATTRIBUTE, named("red"))
    }
}

Error and warning reporting improvements

Gradle provides a rich set of error and warning messages to help you understand and resolve problems in your build.

Simple console rendering for Problem Reports

The Problems API provides structured feedback on build issues, helping developers and tools like IDEs identify and resolve warnings, errors, or deprecations during configuration or runtime.

Previously, a limitation was that problem reports were not displayed in the console output. In this release, we've taken a first step toward full console integration. All problem reports are now rendered in the console output when you configure --warning-mode=all.

Promoted features are features that were incubating in previous versions of Gradle but are now supported and subject to backward compatibility. See the User Manual section on the "Feature Lifecycle" for more information.

The following are the features that have been promoted in this Gradle release.

Fixed issues

Known issues

Known issues are problems that were discovered post-release that are directly related to changes made in this release.

External contributions

We love getting contributions from the Gradle community. For information on contributing, please see gradle.org/contribute.

Reporting problems

If you find a problem with this release, please file a bug on GitHub Issues adhering to our issue guidelines. If you're not sure if you're encountering a bug, please use the forum.

We hope you will build happiness with Gradle, and we look forward to your feedback via Twitter or on GitHub.