Budius
Budius

Reputation: 39836

Test Custom Gradle plugin after Evaluate

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

Answers (2)

dpr
dpr

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

Alexey Nikitin
Alexey Nikitin

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

Related Questions