Reputation: 39836
I'm developing a Gradle custom plugin and I'm having issues on how to test it.
The plugin creates an extension to receive configuration and after evaluation (project.afterEvaluate {
) creates a tasks with the received configuration, those values are @Input
on tasks.
Following the documentation https://docs.gradle.org/current/userguide/custom_plugins.html to create a test for the plugin, I use the following to create the project and apply the plugin
@Before fun setup() {
project = ProjectBuilder.builder().build()
project.pluginManager.apply("my.plugin.name")
and then test that extension got created:
assertTrue(project.extensions.findByName("name") is MyConfigType)
and the task got created:
assertTrue(project.tasks.findByName("mytask") is MyTaskType)
The issue I'm having is that the task is only created afterEvaluate
, so this test is failing. As far as I understood, it has to be afterEvaluate
so that it can receive the configuration values.
So the only way I could see if I could on the test force this project to be evaluated, but how?
Is there maybe a different way to receive values?
Upvotes: 4
Views: 1470
Reputation: 10964
I posted my similar question in the gradle forums and was able to solve the issue: https://discuss.gradle.org/t/unit-test-plugins-afterevaulate/37437/3
Apparently afterEvaluate
is not the best/right place to perform the task creation. If you have a DomainObjectCollection
in your extension and want to create a task for each element in the collection, task creation should be done in the all
-Callback of the collection:
final MyExtension extension = project.getExtensions().create("extension", MyExtension.class);
extension.configurations.all((c) -> {
// register task here
});
If you have simple properties in the extension that are feed to the task as input, you should use lazy configuration:
public class MyExtension {
public final Property<String> property;
public final NamedDomainObjectContainer<Configuration> configurations;
@Inject
public MyExtension(final ObjectFactory objectFactory) {
property = objectFactory.property(String.class).convention("value");
configurations = objectFactory.domainObjectContainer(Configuration.class);
}
}
public abstract class MyTask extends DefaultTask {
@Input
private final Property<String> property = getProject().getObjects().property(String.class);
public Property<String> getProperty() {
return property;
}
}
And the apply method:
public class MyPlugin implements Plugin<Project> {
@Override
public void apply(final Project aProject) {
final MyExtension extension = aProject.getExtensions().create("extension", MyExtension.class);
aProject.getTasks().register("myTask", MyTask.class).configure((t) -> {
t.getProperty().set(extension.property);
});
}
}
Upvotes: 2
Reputation: 664
You should call project.evaluationDependsOn(":")
:
@Before fun setup() {
project = ProjectBuilder.builder().build()
project.pluginManager.apply("my.plugin.name")
project.evaluationDependsOn(":") // <<--
...
}
It executes your afterEvaluate
callback.
Upvotes: 0