Gradle does not copy test resources to build

Viewed 15246

I have a multi project gradle project (spring web), with the following layout:

springweb
 |    build.gradle
 |    settings.gradle
 |_____ services
 |         build.gradle
 |         src/main/java
 |         src/main/resources
 |         src/test/java
 |         src/test/resources
 |             create-data.sql
 |_____ web
 |         build.gradle
 |         src/main/java
 |         src/main/resources
 |         src/main/webapp
 |         src/test/java
 |         src/test/resources

When I try to execute the contents under src/test/resources (init.sql)

commandLine 'psql', '-h', 'localhost', '-d', 'junit', '--username', 'junit', '-f' , sourceSets['test'].output.resourcesDir.toString() + '/create-data.sql'

it failse because the resource is not available in the build directory:

/Users/me/dev/springweb/services/build/resources/test/create-data.sql: No such file or directory

below my root build.gradle:

ext {
    springSecurityGroup = 'org.springframework.security'
    springSecurityVersion = '3.1.4.RELEASE'
    springGroup = 'org.springframework'
    springVersion = '3.2.5.RELEASE'
    hibernateGroup = 'org.hibernate'
    hibernateVersion = '4.2.7.SP1'
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'eclipse'
    sourceSets.all{
        println output.classesDir
    }

    repositories {
        mavenCentral()
    }
}

and the 'services' build.gradle:

task createDb (type:Exec) { 
     println sourceSets['test'].output.resourcesDir.toString()
     commandLine 'psql', '-h', 'localhost', '-d', 'junit', '--username', 'junit', '-f' ,'/Users/me/dev/sip/sip/sip04/src/main/resources/create-table.sql'
}
task fillDb (type:Exec, dependsOn: 'createDb') {
     commandLine 'psql', '-h', 'localhost', '-d', 'junit', '--username', 'junit', '-f' , sourceSets['test'].output.resourcesDir.toString() + '/create-data.sql'
}
test.dependsOn fillDb

dependencies {
    /* zipped */
}

/* Change context path (base url). otherwise defaults to name of project */

I execute it with gradle build:

gradle build
/Users/me/dev/springweb/services/build/classes/main
/Users/me/dev/springweb/services/build/classes/test
/Users/me/dev/springweb/web/build/classes/main
/Users/me/dev/springweb/web/build/classes/test
/Users/me/dev/springweb/services/build/resources/test
:services:compileJava UP-TO-DATE
:services:processResources UP-TO-DATE
:services:classes UP-TO-DATE
:services:jar UP-TO-DATE
:services:assemble UP-TO-DATE
:services:createDb
DROP TABLE
DROP SEQUENCE
zipped
:services:fillDb/Users/me/dev/springweb/services/build/resources/test/create-data.sql: No such file or directory

From the output I learn that the sourceSets are as I expect, but that the test resources are not copied. What is wrong?

2 Answers

Copying of test resources is done by the processTestResources task from the Java plugin. The Java plugin also specifies this as a prerequisite of the test task, so that it happens before the tests are run.

You have told gradle that your fillDb task is also a prerequisite of the test task BUT you have not told it that processTestResources is a prerequisite of your createDb task.

So you could do something like

task createDb (type:Exec, dependsOn: 'processTestResources') { 
...

BTW test resources are things that are made available to the tests via the classpath. I assume your tests don't need actually your sql available on the classpath at runtime, so do they even need to be there?

Gradle uses processTestResources task from the java plugin to generate the test resources. By default the location of the test resources in Module/build/resources/test. If you want to test just the testResources getting generated correctly or not Run the following command:

./gradlew :<Module-name>:processTestResources 

After running the command, check testReources directory. It should contain the correct files.

Another Suggestion Try Segregating all the common logic in a gradle plugin and write a test for Gradle plugin. In that way, you can get confidence over the piece of code. If it works fine or not.

Eg: TestPlugin.groovy

 project.sourceSets {
            test {
                resources {
                    srcDir project.files("${project.projectDir}/<location-of-resources>/")
                }
            }
        }

In this scenario, place your resources in some folder named and tempFile is the resource for test. And the Test for the same: TestPluginSpec.groovy

 @Rule
    TemporaryFolder testProjectDir = new TemporaryFolder()
    File tempFile
    tempFile = testProjectDir.newFile('tempFile')
    buildFile = testProjectDir.newFile('build.gradle')

    buildFile << """
             plugins {
                id 'java'
               }
   """
def "should add test Resources into build/resources/test"(){
        when:
        def result = GradleRunner.create().withProjectDir(testProjectDir.root).withPluginClasspath().withArguments('processTestResources').withDebug(true).build()
        then:
        result.task(":processTestResources").outcome == TaskOutcome.SUCCESS
        and:
        Files.exists(Paths.get("${testProjectDir.root.path}/build/resources/test/tempFile"))
    }
Related