dr jerry
dr jerry

Reputation: 10026

Gradle does not copy test resources to build

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?

Upvotes: 5

Views: 16622

Answers (2)

Lavish
Lavish

Reputation: 720

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"))
    }

Upvotes: 2

Perryn Fowler
Perryn Fowler

Reputation: 2232

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?

Upvotes: 3

Related Questions