Programmatically invoke a gradle task graph in a u

2020-06-03 01:37发布

问题:

I am in the process of writing a custom plugin for gradle and as part of the unit testing I would like to invoke my task but in such away as it's prerequisite tasks are executed.

The actual plugin is unfortunately an internal project so I can't sure the exact source, but I have prepared a unit test that demonstrates the problem:

package toy

import org.gradle.api.Project
import org.gradle.testfixtures.ProjectBuilder
import org.junit.Test

class ToyTasksTest {

    boolean task1Run = false
    boolean task2Run = false

    @Test
    public void taskDependencies(){


        Project p = ProjectBuilder.builder().build()

        p.task("task1") << {
            p.logger.info("task1 running")
            task1Run = true
        }

        def task2 = p.task("task2", dependsOn: 'task1') << {
            p.logger.info("task2 running")
            task2Run = true
        }
        task2.execute() // <--- what magic do I need here instead of .execute()

        assert task2Run == true
        assert task1Run == true
    }
}

The output is:

Assertion failed: 

assert task2Run == true
       |        |
       false    false

The project is available on github if you would like to quickly run the test.

Another way of saying this instead of writing:

task2.execute()

I'd like run the equivalent of:

gradle task2

In the unit test.

回答1:

It seems to me that what you are trying to get here is more of an integration test than a unit test. It was suggested to me in the past by Gradle team members that when writing plugins and task what you want to do is to separate as much as you can/makes sense from your task into POJO and unit test that. For everything else that Gradle does for you and the plumbing, like executing task graph, testing incremental task features and so on you probably want to have integration tests which definitely are slower, that's why you want to unit test as much as possible.

The only problem is that Gradle currently doesn't provide a toolset for writing those integration tests. There is a design spec for that but currently you still have to hand craft a solution if you need one.

You can have a look the one that I using here but keep in mind that it has some classpath issues, that's why this line is necessary.

An example of the other solution that is using GradleConnector and that I found recently can be found here.



回答2:

Luke Daley (Gradle core dev) developed a cool functional testing system for my Gradle plugins, seen in use here.

Similar to @erdi's answer, this is a functional testing solution and does not use Gradle's ProjectBuilder. It requires that you include these utility classes for testing.

I realize that it's not the succinct answer you might have hoped for, but this system has served me very well while I develop a few Gradle plugins.



回答3:

Replace:

task2.execute() // <--- what magic do I need here instead of .execute()

With:

task2.actions.each { Action action ->
     action.execute(task2)
}


回答4:

I use this method for executing tasks in tests:

void executeTask(Task task) {
    task.taskDependencies.getDependencies(task).each {
        subTask -> executeTask(subTask)
    }

    task.execute()
}

Example:

@Test
void testTasksDependency() {
    def first = project.task("first").doLast {
        println "Doing First"
    }

    def second = project.task("second", dependsOn: first).doLast {
        println "Doing Second"
    }

    def third = project.task("third", dependsOn: second).doLast {
        println "Doing Third"
    }

    // Let's call our method
    executeTask(third)

    assertTrue(first.state.executed)
    assertTrue(second.state.executed)
    assertTrue(third.state.executed)
}

Output:

Doing First
Doing Second
Doing Third