Closed u6f6o closed 4 years ago
If I use the same setup with groovy dsl it works though:
plugins {
id 'org.unbroken-dome.test-sets' version '3.0.1'
}
testSets {
integrationTest
}
dependencies {
// Wiremock will only be available in integration tests, but not in unit tests
integrationTestImplementation 'com.github.tomakehurst:wiremock:2.26.3'
}
tasks.withType(Test) {
useJUnitPlatform()
}
I was also hoping to use this, but can't figure out how. Is there a workaround to make this work?
@sean-abbott there is a workaround:
dependencies {
// works
add("integrationTestImplementation", "com.github.tomakehurst:wiremock:2.26.3")
// also works
"integrationTestImplementation"("com.github.tomakehurst:wiremock:2.26.3")
}
looks like you can refer to the configuration as a string and add dynamically, but the configuration isn't being added in the generated Kotlin DSL code.
Awesome. Thank you. If it's not too much trouble, would you mind explaining to a kotlin-and-gradle noob what the mechanisms of working/not working are here, so I can start to form the ability to reason about this?
I totally understand if that's too much trouble, 'cause definitely not your problem. :-)
Hard to be succinct on the inner workings of Gradle here, but a couple starting points:
dependencies
block is a closure on this interface: https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html, so all its methods and properties of it are available within the dependencies
block.Definitely recommend reading through the Gradle User Manual and the DSL reference if you haven't and want a deeper understanding.
Similarly, the API dependencies of testSets are also broken
The workaround doesn't appear to work for me. I have, abbreviated:
allprojects {
repositories {
jcenter()
mavenCentral()
gradlePluginPortal()
//snip
}
subprojects {
apply(plugin = "org.unbroken-dome.test-sets")
//snip
dependencies {
//snip
implementation(platform("org.testcontainers:testcontainers-bom:1.14.3"))
// works, but commented to try
// testImplementation("org.testcontainers:mysql")
// "integrationTestImplementation"("org.testcontainers:mysql") // fails with Configuration with name 'integrationTestImplementation' not found
// add("integrationTestImplementation", "org.testcontainers:msyql") // same
}
testSets {
val integrationTest by creating {}
}
}
(this is my top level build.gradle.kts). I understand my coordinates might not be correct for the workaround, BUT the complaints isn't the coordinates it's that it can't find the configuration.
Sorry for being late to the discussion... this is a "limitation" of the Kotlin DSL, there's nothing I can do about it in the plugin.
When using Gradle with Groovy DSL, any "method" that is not recognized (for example, the name of a configuration inside the dependencies
block), Groovy calls a special methodMissing
method as a fallback to handle this. This is part of the dynamic programming features of Groovy.
Kotlin has no such dynamic resolution mechanism, but it supports extension methods and an invoke
operator fun (which lets you "call" anything, including a string, by putting parentheses and possibly arguments after it. The creators of the Gradle Kotlin DSL used this to achieve something similar to the dynamic Groovy methods, but you have to surround the names in quotes so they are passed to operator fun String.invoke()
:
dependencies {
"integrationTestImplementation"("com.example:foo:1.2.3")
}
This is not only true inside the dependencies
block but pretty much in any DSL container that supports named objects, e.g. tasks
.
Now, what the Kotlin DSL does in addition if the java
plugin is applied, is that they statically define some extension methods for well-known configuration names like implementation
, testCompileOnly
and so forth. That's why you can use these without quotes.
Any other configuration names which are dynamically determined by the build script must be enclosed in quotes. The only way around this would be if custom plugins had access to the Kotlin DSL stub generation (or whatever it's called). This stub consists of a just-in-time generated Kotlin class library tailored to the plugins used in their build script. To my knowledge, this is not something that Gradle has published an API for or allows third-party plugins to modify.
Has anyone got it working with a multi-project setup? Seems testSets
can't be configured in subprojects
block:
subprojects {
// with declarative DSL (i.e. plugin id("org.unbroken-dome.test-sets") set above)
testSets {
}
apply(plugin = "org.unbroken-dome.test-sets")
configure<TestSetsPlugin> {
}
}
Both methods get this error: Extension of type 'TestSetContainer' does not exist.
Didn't have this problem when using groovy.
Edit: it works if I apply in each submodule build.gradle.kts
(i.e. no subprojects
or allprojects
block required). But duplicate code :/
I added the gradle-testsets-plugin to our existing kotlin dsl build files and initially everything worked smoothly. After I moved the dependencies to
integrationTestImplementation
though, the build stopped working with the following exception:When I remove the dependency, the build works again. Here is a little reproducer:
Could it be related to https://stackoverflow.com/questions/52904603/integration-tests-with-gradle-kotlin-dsl maybe?