Testing a Settings plugin

Hi Gradle folks,

I’ve created a plugin that implements Plugin<Settings> and I would like to create some sort of integration test for it.
Is there something like ProjectBuilder for Settings? I noticed SettingsPluginIntegrationSpec, AbstractIntegrationSpec & AbstractIntergationTest in the gradle integTest project though I found no way to depend on it, apparently it’s not published.

I’ve tried working with gradleTestKit, but even after the classpath manipulation (and the discovery that the old plugin application notation is not supported in the test kit) I found that Settings plugins can only be applied using the old notation.

Is there a way to test Settings plugins without resorting to actually executing gradle outside of test code or replicating the integTest code?


At the moment there’s not a way to create a Settings instance like you can create a Project instance with the ProjectBuilder.

I’d rather go down the TestKit route. You can still apply the plugin with the “old” apply notation if you want to. You just need to add the plugin classes to the build script’s classpath manually. Can you explain why it matters to your plugin how it is applied in your test setup?

You can find a bunch of examples for these use cases in this test class of ours.

It doesn’t matter.

All the plugin application in that file (other then a test running a task running a standard test) are for the groovy plugin which is implicitly available on all builds, not a custom one.

I followed the classpath manipulation to the letter.
How would I apply the plugin in the settings?
apply plugin: 'someplugin' resulted at plugin not found.
apply plugin: com.something.SomePlugin resulted at could not find property ‘com’

Checking the plugin-classpath.txt file I see all the relevant jars and /build/classes/main dir and /build/resources/main dir.
I’ve debbuged the setup code and the DefaultClassPath instance seems to be created successfully.
I’ve even explicitly added all classes and resources to the plugin-classpath.txt file but to no avail.

Everything works when I test the plugin manually, so it’s not the gradle-plugins manifest.

Is there something I’m missing? should I include some pseudo repository in the settings file before applying the plugin?

My code is essentially a duplicate of the classpath manipulation to the letter.
The test is as follows

buildFile << '''apply plugin: \'java\' 
                    repositories { jcenter() }
                    task nothing << { println 'nothing' }

I added a test case to TestKitEndUserIntegrationTest.groovy that demonstrates the required setup for testing a Settings plugin. Hope this helps.

Use the gradleTest plugin. Dump a copy of the settings.gradle you want to test with in the src/gradleTest/TEST_NAME/ folder.

P.S. You can use the TestKit API for htis, but you’ll need at least the RC version of 2.9 to have something useful IMHO. For all other cases in this context when you are using an older version of Gradle you are still better off using the gradleTest plugin. It has the advantage of testing your plugin against a whole set of Gradle versions.

This functionality was already working with Gradle 2.6. You don’t have to use Gradle 2.9-RC for that. I don’t think @Boaz_Jan was necessarily asking for cross-version testing functionality here.

Thanks @bmuschko!

The missing code part was
settingsFile << """ buildscript { dependencies { classpath files($pluginClasspath) } } """
plus some manipulation on the pluginClasspath.

I think it’s worth to mention in the documentation that the withPluginClasspath of the GradleRunner does not effect the settings evaluation and needs to be defined manually…


Also, withProjectDir does not effect settings evaluation, I’m accessing a file within the Settings plugin and passing a relative path to the settings.gradle location does not work. absolute path does.

Can you provide some sample code? At the moment I don’t fully understand your problem.

The issue is simple, GradleRunner has 2 methods that don’t take effect on Settings:

  • withProjectDir
  • withPluginClasspath

withProjectDir should set the current working dir thus allowing us to use relative paths. My test shows that this does not apply to relative paths used from a settings plugin.

withPluginClasspath should set the injected plugin classpath, but it does not set it for the settings as seen by your example.

Your logic in the Settings plugin should determine the path based on Settings.getSettingsDir() to ensure the proper directory. If you don’t, the path used for executing your build is used which is not the path the project you create in the tmp directory. You’d run into the same issue if you’d execute a build that uses your plugin from a different directory than the one that hosts your settings.gradle.

import org.gradle.api.Plugin
import org.gradle.api.initialization.Settings

class SettingsPlugin implements Plugin<Settings> {
    void apply(Settings settings) {
        println new File(settings.settingsDir, 'test.test').text