GradleRunner testing tasks that create files

(Philip Cheong) #1

I encountered some unexpected behaviour with the GradleRunner when testing a task that creates a file in the project root directory.

I was expecting the file to be created in the temporary project root directory that I passed to the GradleRunner but it is actually created in my code root directory.

My integration test is pretty straight forward:

public class integrationTests {

    @Rule public final TemporaryFolder testProjectDir = new TemporaryFolder()

    public void setup() throws IOException {

        buildFile = testProjectDir.newFile('build.gradle')
        buildFile << """
            plugins {
                id 'my.custom.plugin'
        propertiesFile = testProjectDir.newFile('')
        propertiesFile << """

    public void doTest() {

        BuildResult result = GradleRunner.create()
                .withArguments("SomeTaskThatCreatesAFileInTheProjectRoot") //this task creates a file in my code root

        // what files do we have in the testProjectDir root? Only build.gradle and created above
        testProjectDir.getRoot().eachFile() { file->
            println file.getAbsolutePath()
        result.task(":SomeTaskThatCreatesAFileInTheProjectRoot").outcome == "SUCCESS"

Is this the expected behavior of the GradleRunner or is it just how groovy behaves that I need to handle myself? As the file in question is generated from running a test, I’d also like it to be deleted after the test. Ideally I could put it in the testProjectDir that holds my test build.gradle and which is disposed of at the end of my test class by junit, but then I need to pass that temp directory location to SomeTaskThatCreatesAFileInTheProjectRoot as an -P argument basically?

(Philip Cheong) #2

It took a fair amount of messing around to get it right but things became a lot easier after learning about the spock test framework.

In the end the code looks something like this:

import org.junit.rules.TemporaryFolder
import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.BuildResult
import static org.gradle.testkit.runner.TaskOutcome.*
import spock.lang.Specification
import spock.lang.Shared

class integrationTests extends Specification{

    @Shared TemporaryFolder testProjectDir = new TemporaryFolder()
    @Shared File buildFile
    @Shared File propertiesFile

    def setupSpec() {
        buildFile = testProjectDir.newFile('build.gradle')
        // setup temporary build file to apply our plugin
        buildFile << """
            plugins {
                id ''
        // is a temporary file generated during the build before the tests run
        // that contains information that jacoco needs to produce code coverage correctly
        // see the createTestKitFiles task below
        propertiesFile = writeFile('', getResourceUrl('').text)
        propertiesFile << """

def "some integration test"() {
    // Build up our argument list for the gradle runner
         List<String> argList = new ArrayList<String>();
         argList.add("-Pproject_directory=" + testProjectDir.root)

         def result = GradleRunner.create()
        result.output.contains("some interesting string")
        result.task(":task_to_run").outcome == SUCCESS

For completeness sake, here is the createTestkitFiles task:

task createTestkitFiles {
     def outputDir = file("$buildDir/testkitFiles")

    inputs.files configurations.jacocoRuntime
    outputs.dir outputDir

    // to combine the jacoco test coverage reports we need to pass some arguments to the jvm
    // see here for more details
    doLast {
        // annoying stuff if you have to build on windows.
        String jacocoPath = configurations.jacocoRuntime.asPath.replace('\\', '/')
        file("$outputDir/").text = "org.gradle.jvmargs=-javaagent:${jacocoPath}=destfile=$buildDir/jacoco/integTest.exec"