Search

Dark theme | Light theme

February 5, 2024

Gradle Goodness: Continuous Testing For Java Projects

The command line option --continuous or the short version -t enables Gradle’s continous build. For a continuous build Gradle will keep on running and will re-execute the tasks we invoked if the input or of the input of one of the depended tasks has changed. For a project with the java plugin we can use this option for the test task. Gradle will run the test task and after the task has been executed Gradle will wait for any changes in the input of the task. This means if we change our Java test code in src/test/java and save the source file Gradle will re-execute the test task and show the output. But also if the input of other tasks changes, that the test task depends on, the test is re-executed. So also changes in source files in our src/main/java directory will trigger a re-execute of the test task, because the test task depends on the compileJava task, and the compileJava task has the src/main/java directory as input.

In the following example output we invoked the test task with the --continuous option. On the first run there was an assertion failure. We fixed the code in src/main/java and saved the file. Without having to restart Gradle we see that our assertion succeeded on the second test task run.

$ ./gradlew --continuous test

> Task :app:test FAILED

AppTest > application has a greeting FAILED
    Condition not satisfied:

    result == "Hello World!!"
    |      |
    |      false
    |      2 differences (84% similarity)
    |      Hello (w)orld!(-)
    |      Hello (W)orld!(!)
    Hello world!
        at org.example.AppTest.application has a greeting(AppTest.groovy:17)

1 test completed, 1 failed

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:test'.
> There were failing tests. See the report at: file:///Users/mrhaki/Projects/mrhaki.com/java/app/build/reports/tests/test/index.html

* Try:
> Run with --scan to get full insights.

BUILD FAILED in 3s
3 actionable tasks: 1 executed, 2 up-to-date

Waiting for changes to input files... (ctrl-d to exit)
modified: /Users/mrhaki/Projects/mrhaki.com/java/app/src/main/java/org/example/App.java
Change detected, executing build...


BUILD SUCCESSFUL in 4s
3 actionable tasks: 3 executed

Waiting for changes to input files... (ctrl-d to exit)
<=============> 100% EXECUTING [53s]
> IDLE
> IDLE

To stop continuous builds we press Ctrl+C.

To have some nice output we want to use the full exception format for our test logging. In the following example build file we configure this for our test task in the testLogging block:

// File: build.gradle.kts
...
testing {
    suites {
        val test by getting(JvmTestSuite::class) {
            targets {
                all {
                    testTask.configure {
                        testLogging {
                            exceptionFormat = TestExceptionFormat.FULL
                        }
                    }
                }
            }
        }
    }
}
...

Now we can run the test task with the --continuous option and work on our source files and tests in our IDE. On each save of a source file the test task is executed again and we can immediately see the output of the test run.

Written with Gradle 8.6