Gradle plugins
Gradle build logic can often become quite complex. Much like production code, it should be well tested to discover edge cases.
All types of Gradle plugins can be tested (settings plugins, project plugins, precompiled script plugins…).
Configuration
Add a dependency on dev.opensavvy.prepared:compat-gradle
to use the features on this page.
See the reference.
Prepared provides helpers to entire Gradle builds inside tests. Typically, this is done to test a plugin. In this example, we will create a plugin and test its behavior.
The project should be similar to:
src/
main/kotlin/foo/bar/baz/
MainPlugin.kt
test/kotlin/foo/bar/baz/
MainPluginTest.kt
build.gradle.kts
plugins {
`kotlin-dsl` //(1)!
}
gradlePlugin {
plugins {
create("my-convention-plugin") {
id = "main-plugin"
implementationClass = "foo.bar.baz.MainPlugin"
}
}
}
dependencies {
testImplementation("dev.opensavvy.prepared:runner-kotlin-test:VERSION_HERE") //(2)!
testImplementation("dev.opensavvy.prepared:compat-gradle:VERSION_HERE")
}
- The
kotlin-dsl
plugin allows creating Gradle plugins compatible with the current Gradle version. Do not apply thekotlin("jvm")
plugin! - See available versions here.
import org.gradle.api.*
abstract class MainPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.tasks.register("createFileTask") {
val myFile = File("myfile.txt")
myFile.createNewFile()
myFile.writeText("HELLO FROM MY PLUGIN")
}
}
}
Now, we can write tests for this plugin:
class MainPluginTest : TestExecutor() {
override fun SuiteDsl.register() {
val setup by prepared { //(1)!
gradle.settingsKts("""
include("foo")
""".trimIndent()) //(2)!
gradle.rootProject.buildKts("") //(3)!
gradle.project("foo").buildKts("""
plugins {
id("main-plugin")
}
""".trimIndent()) //(4)!
}
val myFile by gradle.project("foo").dir() / "myfile.txt"
test("The task :createFileTask creates a file") {
setup() //(5)!
gradle.runner()
.withPluginClasspath() //(6)!
.withArguments("createFileTask") //(7)!
.build()
check(myFile().readText() == "HELLO FROM MY PLUGIN")
}
}
}
- Declare the project setup in a prepared value for convenience: we will be able to reuse it between multiple tests.
- Use the
gradle
extension point and itssettingsKts
function to create thesettings.gradle.kts
file. - Create an empty root
build.gradle.kts
file. - Create a
foo/build.gradle.kts
file that applies our plugin. - Invokes the prepared value we defined earlier.
- Injects the current classpath into the build. Since the plugin we are building is in the current classpath, it will be injected into the test project, which is why we didn't need to specify a version when using
id("my-plugin")
. - The command-line arguments passed when invoking Gradle.
Each test using the gradle
extension point creates its own temporary directory in which all files and the build happen. Its path is always logged to the standard output: if the test fails, you can visit it yourself easily to inspect the state of all files.
If the test is successful, the temporary directory is deleted automatically.
Official tutorial
Learn more about writing plugins in the official documentation. Prepared is just syntax sugar on top of the official tooling, so all techniques described there should work with Prepared.