Gradle newbie: unit tests not running

Hello Gradle folks

I’m a new Gradle user.

To learn about Gradle, I followed the well-written tutorial in Building Java Applications Sample.

Then I configured Gradle in an existing Java application. Many Gradle tasks run, but they don’t run the unit tests, even after ./gradlew clean or when I modify the unit test code.

To debug, I’ve tried running ./gradlew clean test --info --tests RewriteAttributeTagsTest where RewriteAttributeTagsTest is a unit test I wrote, and then modifying the unit test. It does compile, because if it contains garbage the compile dies with an appropriate error. But it doesn’t run the tests, because if I create a test that fails that doesn’t get reported. Unfortunately the output of --info does not enlighten me.

Here are the key files:
build.gradle:

plugins {
  id 'org.springframework.boot' version '2.6.4'
  id 'io.spring.dependency-management' version '1.0.11.RELEASE'
  id 'java'
  // coverage testing:
  // id 'jacoco'
  // id 'test-report-aggregation'
  // id 'jacoco-report-aggregation'
  // Apply the application plugin to add support for building a CLI application in Java.
  // See https://docs.gradle.org/current/samples/sample_building_java_applications.html
  id 'application'
}

group = 'org.mountsinai'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = "15"

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
  implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
  testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
  runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
  implementation group: 'org.springframework', name: 'spring-aspects', version: '5.3.15'
  implementation group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '3.0.0'
  implementation group: 'com.jayway.jsonpath', name: 'json-path', version: '2.7.0'
  implementation group: 'com.github.pcj', name: 'google-options', version: '1.0.0'
  implementation 'com.google.code.gson:gson:2.9.0'
}

// See https://docs.gradle.org/current/samples/sample_building_java_applications.html
application {
    // Define the main class for the application.
    mainClass = 'org.mountsinai.IRWMetadataIntegration.IrwMetadataIntegrationApplication'
}

// Following guidance in https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html
// and https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-running-unit-tests-with-gradle/
test {

  // explicitly include all tests in src/test/java/org/mountsinai/
  include 'src/test/java/org/mountsinai/**'

  // show standard out and standard error of the test JVM(s) on the console
  testLogging.showStandardStreams = true

  // Fail the 'test' task on the first test failure
  failFast = true

  useJUnitPlatform()    // Configure for Junit5 == Jupiter
  minHeapSize = "1024m" // initial heap size
  maxHeapSize = "2048m" // maximum heap size
}
targetCompatibility = JavaVersion.VERSION_15

bootRun {
  jvmArgs = [ "-Dspring.output.ansi.enabled=always",
        "-Dcom.sun.management.jmxremote",
        "-Dspring.jmx.enabled=true",
        "-Dspring.liveBeansView.mbeanDomain",
        "-Dspring.application.admin.enabled=true",
        "-Dfile.encoding=UTF-8"
  ]
}

// location of test reports, as per https://docs.gradle.org/current/userguide/java_testing.html#test_reporting
reporting.baseDir = "my-reports"
testResultsDirName = "$buildDir/my-test-results"

tasks.register('showDirs') {
    doLast {
        logger.quiet(rootDir.toPath().relativize(project.reportsDir.toPath()).toString())
        logger.quiet(rootDir.toPath().relativize(project.testResultsDir.toPath()).toString())
    }
}

settings.gradle:

rootProject.name = 'IRWMetadataIntegration'
include('irw_app')

The output of ./gradlew clean test --info --tests RewriteAttributeTagsTest:

$ ./gradlew clean test --info  --tests RewriteAttributeTagsTest
Initialized native services in: /Users/arthur_at_sinai/.gradle/native
Initialized jansi services in: /Users/arthur_at_sinai/.gradle/native
Found daemon DaemonInfo{pid=43075, address=[90e7da32-ae99-4d6f-83b7-069610fc4786 port:64700, addresses:[/127.0.0.1]], state=Idle, lastBusy=1666812761701, context=DefaultDaemonContext[uid=d8625191-d029-47c5-bc44-aa3e9cc38f4a,javaHome=/usr/local/Cellar/openjdk@17/17.0.5/libexec/openjdk.jdk/Contents/Home,daemonRegistryDir=/Users/arthur_at_sinai/.gradle/daemon,pid=43075,idleTimeout=10800000,priority=NORMAL,daemonOpts=--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.base/java.lang=ALL-UNNAMED,--add-opens,java.base/java.lang.invoke=ALL-UNNAMED,--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.base/java.nio.charset=ALL-UNNAMED,--add-opens,java.base/java.net=ALL-UNNAMED,--add-opens,java.base/java.util.concurrent.atomic=ALL-UNNAMED,-XX:MaxMetaspaceSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant]} however its context does not match the desired criteria.
Java home is different.
Wanted: DefaultDaemonContext[uid=null,javaHome=/Users/arthur_at_sinai/Library/Java/JavaVirtualMachines/openjdk-17.0.2/Contents/Home,daemonRegistryDir=/Users/arthur_at_sinai/.gradle/daemon,pid=10821,idleTimeout=null,priority=NORMAL,daemonOpts=--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.base/java.lang=ALL-UNNAMED,--add-opens,java.base/java.lang.invoke=ALL-UNNAMED,--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.base/java.nio.charset=ALL-UNNAMED,--add-opens,java.base/java.net=ALL-UNNAMED,--add-opens,java.base/java.util.concurrent.atomic=ALL-UNNAMED,-XX:MaxMetaspaceSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant]
Actual: DefaultDaemonContext[uid=d8625191-d029-47c5-bc44-aa3e9cc38f4a,javaHome=/usr/local/Cellar/openjdk@17/17.0.5/libexec/openjdk.jdk/Contents/Home,daemonRegistryDir=/Users/arthur_at_sinai/.gradle/daemon,pid=43075,idleTimeout=10800000,priority=NORMAL,daemonOpts=--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.base/java.lang=ALL-UNNAMED,--add-opens,java.base/java.lang.invoke=ALL-UNNAMED,--add-opens,java.base/java.util=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.prefs/java.util.prefs=ALL-UNNAMED,--add-opens,java.base/java.nio.charset=ALL-UNNAMED,--add-opens,java.base/java.net=ALL-UNNAMED,--add-opens,java.base/java.util.concurrent.atomic=ALL-UNNAMED,-XX:MaxMetaspaceSize=256m,-XX:+HeapDumpOnOutOfMemoryError,-Xms256m,-Xmx512m,-Dfile.encoding=UTF-8,-Duser.country=US,-Duser.language=en,-Duser.variant]

  Looking for a different daemon...
The client will now receive all logging from the daemon (pid: 51022). The daemon log file: /Users/arthur_at_sinai/.gradle/daemon/7.5.1/daemon-51022.out.log
Starting 48th build in daemon [uptime: 2 hrs 51 mins 5.624 secs, performance: 99%, non-heap usage: 33% of 256 MiB]
Using 8 worker leases.
Now considering [/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2, /Users/arthur_at_sinai/tmp/learn_Gradle/sample_building_java_applications] as hierarchies to watch
Watching the file system is configured to be enabled if available
File system watching is active
Starting Build
Settings evaluated using settings file '/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/settings.gradle'.
Projects loaded. Root project using build file '/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/build.gradle'.
Included projects: [root project 'IRWMetadataIntegration', project ':irw_app']

> Configure project :
Evaluating root project 'IRWMetadataIntegration' using build file '/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/build.gradle'.

> Configure project :irw_app
Evaluating project ':irw_app' using build file '/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build.gradle'.
Applying dependency management to configuration 'bootArchives' in project 'irw_app'
Applying dependency management to configuration 'archives' in project 'irw_app'
Applying dependency management to configuration 'default' in project 'irw_app'
Applying dependency management to configuration 'implementation' in project 'irw_app'
Applying dependency management to configuration 'compileOnly' in project 'irw_app'
Applying dependency management to configuration 'compileClasspath' in project 'irw_app'
Applying dependency management to configuration 'annotationProcessor' in project 'irw_app'
Applying dependency management to configuration 'runtimeOnly' in project 'irw_app'
Applying dependency management to configuration 'runtimeClasspath' in project 'irw_app'
Applying dependency management to configuration 'testImplementation' in project 'irw_app'
Applying dependency management to configuration 'testCompileOnly' in project 'irw_app'
Applying dependency management to configuration 'testCompileClasspath' in project 'irw_app'
Applying dependency management to configuration 'testAnnotationProcessor' in project 'irw_app'
Applying dependency management to configuration 'testRuntimeOnly' in project 'irw_app'
Applying dependency management to configuration 'testRuntimeClasspath' in project 'irw_app'
Applying dependency management to configuration 'testResultsElementsForTest' in project 'irw_app'
Applying dependency management to configuration 'apiElements' in project 'irw_app'
Applying dependency management to configuration 'runtimeElements' in project 'irw_app'
Applying dependency management to configuration 'mainSourceElements' in project 'irw_app'
Applying dependency management to configuration 'developmentOnly' in project 'irw_app'
Applying dependency management to configuration 'productionRuntimeClasspath' in project 'irw_app'
All projects evaluated.
Task name matched 'clean'
Task name matched 'test'
Selected primary task 'clean' from project :
Selected primary task 'test' from project :
Tasks to be executed: [task ':irw_app:clean', task ':irw_app:compileJava', task ':irw_app:processResources', task ':irw_app:classes', task ':irw_app:compileTestJava', task ':irw_app:processTestResources', task ':irw_app:testClasses', task ':irw_app:test']
Tasks that were excluded: []
Resolve mutations for :irw_app:clean (Thread[Execution worker,5,main]) started.
Resolve mutations for :irw_app:clean (Thread[Execution worker,5,main]) completed. Took 0.0 secs.
:irw_app:clean (Thread[Execution worker,5,main]) started.
destroyer locations for task group 0 (Thread[Execution worker Thread 2,5,main]) started.
destroyer locations for task group 0 (Thread[Execution worker Thread 2,5,main]) completed. Took 0.0 secs.

> Task :irw_app:clean UP-TO-DATE
Caching disabled for task ':irw_app:clean' because:
  Build cache is disabled
Task ':irw_app:clean' is not up-to-date because:
  Task has not declared any outputs despite executing actions.
:irw_app:clean (Thread[Execution worker,5,main]) completed. Took 0.002 secs.
Resolve mutations for :irw_app:compileJava (Thread[included builds,5,main]) started.
Resolve mutations for :irw_app:compileJava (Thread[included builds,5,main]) completed. Took 0.0 secs.
:irw_app:compileJava (Thread[Execution worker,5,main]) started.

> Task :irw_app:compileJava
Resolving global dependency management for project 'irw_app'
Excluding []
Excluding []
Caching disabled for task ':irw_app:compileJava' because:
  Build cache is disabled
Task ':irw_app:compileJava' is not up-to-date because:
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/main has been removed.
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/main/org has been removed.
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/main/org/mountsinai has been removed.
The input changes require a full rebuild for incremental task ':irw_app:compileJava'.
Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
Compiling with toolchain '/Users/arthur_at_sinai/Library/Java/JavaVirtualMachines/openjdk-17.0.2/Contents/Home'.
Compiling with JDK Java compiler API.
Class dependency analysis for incremental compilation took 0.004 secs.
Created classpath snapshot for incremental compilation in 0.017 secs.
:irw_app:compileJava (Thread[Execution worker,5,main]) completed. Took 1.008 secs.
Resolve mutations for :irw_app:processResources (Thread[Execution worker,5,main]) started.
Resolve mutations for :irw_app:processResources (Thread[Execution worker,5,main]) completed. Took 0.0 secs.
:irw_app:processResources (Thread[Execution worker,5,main]) started.

> Task :irw_app:processResources
Caching disabled for task ':irw_app:processResources' because:
  Build cache is disabled
Task ':irw_app:processResources' is not up-to-date because:
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/main has been removed.
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/main/application.properties has been removed.
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/main/attributes.json has been removed.
:irw_app:processResources (Thread[Execution worker,5,main]) completed. Took 0.039 secs.
Resolve mutations for :irw_app:classes (Thread[Execution worker Thread 6,5,main]) started.
Resolve mutations for :irw_app:classes (Thread[Execution worker Thread 6,5,main]) completed. Took 0.0 secs.
:irw_app:classes (Thread[included builds,5,main]) started.

> Task :irw_app:classes
Skipping task ':irw_app:classes' as it has no actions.
:irw_app:classes (Thread[included builds,5,main]) completed. Took 0.0 secs.
Resolve mutations for :irw_app:compileTestJava (Thread[Execution worker Thread 6,5,main]) started.
Resolve mutations for :irw_app:compileTestJava (Thread[Execution worker Thread 6,5,main]) completed. Took 0.0 secs.
:irw_app:compileTestJava (Thread[included builds,5,main]) started.

> Task :irw_app:compileTestJava
Excluding []
Excluding []
Caching disabled for task ':irw_app:compileTestJava' because:
  Build cache is disabled
Task ':irw_app:compileTestJava' is not up-to-date because:
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/test has been removed.
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/test/org has been removed.
  Output property 'destinationDirectory' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/classes/java/test/org/mountsinai has been removed.
The input changes require a full rebuild for incremental task ':irw_app:compileTestJava'.
Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
Compiling with toolchain '/Users/arthur_at_sinai/Library/Java/JavaVirtualMachines/openjdk-17.0.2/Contents/Home'.
Compiling with JDK Java compiler API.
Note: /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/src/test/java/org/mountsinai/IRWMetadataIntegration/service/IRWMetadataProcessorTest.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
Class dependency analysis for incremental compilation took 0.002 secs.
Created classpath snapshot for incremental compilation in 0.024 secs.
:irw_app:compileTestJava (Thread[included builds,5,main]) completed. Took 0.488 secs.
Resolve mutations for :irw_app:processTestResources (Thread[Execution worker Thread 3,5,main]) started.
Resolve mutations for :irw_app:processTestResources (Thread[Execution worker Thread 3,5,main]) completed. Took 0.0 secs.
:irw_app:processTestResources (Thread[Execution worker Thread 3,5,main]) started.

> Task :irw_app:processTestResources
Caching disabled for task ':irw_app:processTestResources' because:
  Build cache is disabled
Task ':irw_app:processTestResources' is not up-to-date because:
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/test has been removed.
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/test/application.properties has been removed.
  Output property 'destinationDir' file /Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2/irw_app/build/resources/test/create_test_data.sql has been removed.
:irw_app:processTestResources (Thread[Execution worker Thread 3,5,main]) completed. Took 0.099 secs.
Resolve mutations for :irw_app:testClasses (Thread[included builds,5,main]) started.
Resolve mutations for :irw_app:testClasses (Thread[included builds,5,main]) completed. Took 0.0 secs.
:irw_app:testClasses (Thread[Execution worker Thread 2,5,main]) started.

> Task :irw_app:testClasses
Skipping task ':irw_app:testClasses' as it has no actions.
:irw_app:testClasses (Thread[Execution worker Thread 2,5,main]) completed. Took 0.0 secs.
Resolve mutations for :irw_app:test (Thread[Execution worker Thread 2,5,main]) started.
Resolve mutations for :irw_app:test (Thread[Execution worker Thread 2,5,main]) completed. Took 0.0 secs.
:irw_app:test (Thread[included builds,5,main]) started.
producer locations for task group 1 (Thread[Execution worker Thread 2,5,main]) started.
producer locations for task group 1 (Thread[Execution worker Thread 2,5,main]) completed. Took 0.0 secs.

> Task :irw_app:test NO-SOURCE
Skipping task ':irw_app:test' as it has no source files and no previous output files.
:irw_app:test (Thread[included builds,5,main]) completed. Took 0.0 secs.

BUILD SUCCESSFUL in 2s
5 actionable tasks: 4 executed, 1 up-to-date
Watched directory hierarchies: [/Users/arthur_at_sinai/gitOnMyLaptopLocal/sc_repos/irw_metadata_to_msdw2, /Users/arthur_at_sinai/tmp/learn_Gradle/sample_building_java_applications]
[sc_repos/irw_metadata_to_msdw2]$ 

The output of ./gradlew clean test --info --tests RewriteAttributeTagsTest.

Thanks for your attention.
Arthur

Versions:

$ ./gradlew -v

------------------------------------------------------------
Gradle 7.5.1
------------------------------------------------------------

Build time:   2022-08-05 21:17:56 UTC
Revision:     d1daa0cbf1a0103000b71484e1dbfe096e095918

Kotlin:       1.6.21
Groovy:       3.0.10
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          17.0.2 (Oracle Corporation 17.0.2+8-86)
OS:           Mac OS X 11.6 x86_64

The info output says your test task is skipped because there are no source files.
This is most probably caused by that bogus include you have.
Should probably be include 'org/mountsinai/**' if you really want to restrict the test being run opposed to everything in src/test/*.

Thanks Björn, that’s really helpful.

I think you’re saying that include in the test script block specifies the source code to test, not the tests to include. That’s a crucial concept. I obtained the idea from the Test API documentation, which needs to be clearer in several places in my opinion.

Simply removing it works, presumably because gradle automatically recognizes all of the java code in the application, distinguishes the test code, and considers the remaining java code to be source.

And you’re saying that the crucial lines in the --info output are

> Task :irw_app:test NO-SOURCE
Skipping task ':irw_app:test' as it has no source files and no previous output files.

which explain why test isn’t being run.

Thanks again

I think you’re saying that include in the test script block specifies the source code to test, not the tests to include.

No, you tried to include source files.
The output “no source files” is a bit misleading here.
It means sources for the task which in this case are the compled class files.

Simply removing it works, presumably because gradle automatically recognizes all of the java code in the application, distinguishes the test code, and considers the remaining java code to be source.

No, it distinguishes test code from production code by the source directory set it is in.
src/main/... contains production stuff, src/test/... contains test stuff.

Thanks for the clarification Bjorn. I believe that you’re pointing out that source has two very different meanings:

  • source as in “Java source code”
  • source as in “the source antecedents in a dependency relationship”

But I’m still unclear on what an include statement means in the test script block. What types of files should it specify?

Regards
Arthur

It’s Björn, or Björn, not Bjorn.

The word “source” can have many meanings, but I don’t know why you mention “dependency relationships” now, we had nothing about dependencies. In this case it is source at in source code vs source as in the input of the task.

But I’m still unclear on what an include statement means in the test script block. What types of files should it specify?

As I already said. Nothing of you want to run all tests. Otherwise class files, starting with the package.