chrmelchior
05/25/2023, 1:57 PMkotlin {
sourceSets {
val commonMain by getting {
dependencies {
// This will pull in library-base-android for both
// Android Unit Test and Instrumented Tests
implementation("io.realm.kotlin:library-base:1.10.0-SNAPSHOT")
}
}
val androidUnitTest by getting {
dependencies {
// Here I need to override the library-base-android variant
// with the library-base-jvm dependency.
}
}
val androidInstrumentedTest by getting {
dependencies {
// This should continue to use the library-base-android variant.
}
}
}
}
Anyone have any idea on how to achieve this? 🤔
Can I make a release of the library with some metadata for the source set resolution to “just work” or is there some way to manipulate the Gradle depedency inside the the two different test closures?Jeff Lockhart
05/25/2023, 5:10 PMandroidInstrumentedTest and androidUnitTest source sets should be added to: https://kotlinlang.slack.com/archives/C3PQML5NU/p1682443478051419?thread_ts=1675016886.869689&cid=C3PQML5NU
Note the API has been updated slightly since this post. You now call it directly from the androidTarget() declaration (which replaces the previous android() target declaration):
androidTarget {
publishLibraryVariants("release")
instrumentedTestVariant.sourceSetTree.set(SourceSetTree.test)
unitTestVariant.sourceSetTree.set(SourceSetTree.unitTest)
}
You can check it out in the latest 1.9.0-Beta release: https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/Jeff Lockhart
05/25/2023, 5:14 PMandroidUnitTest, if you're supporting the JVM target as well, I'd just use the jvmTest source set to run those tests and omit the androidUnitTest by assigning it to the unitTest source set tree as my code above does. This is what I'm doing in my library.chrmelchior
05/25/2023, 5:45 PMandroid.os.Build (which is not available in the unit test variant), but our users shouldn’t care about that. We also load some native code, which behaves very different on Android devices vs. JVM.
All of those things are kinda hidden for people right now because they just interact with the Multiplatform API, and it “just works” because the variant metadata allows Gradle to select the proper dependency based on the projet type.
But the androidUnitTest is some sort of hybrid between Jvm and Android which makes it hard for libraries to handle (as far as I can tell).
Not sure if that made sense?Jeff Lockhart
05/25/2023, 5:58 PMandroidUnitTest source set? Or just commonTest?Jeff Lockhart
05/25/2023, 6:00 PMandroid or jvm variant, depending on their use case, right?Jeff Lockhart
05/25/2023, 6:10 PMAs I understand the new API it “just” allows decoupling of unit tests from instrumentation tests?I don't know that I'd call it decoupling these test source sets. They have always been their own separate source sets, but a sort of anomaly as they don't fit with the regular KMP source set layout (main + test). This API now gives control over which source set tree each Android test source set inherits from. In Kotlin <=1.7, both unit and instrumented tests inherited from the
commonTest source set tree. In 1.8, the androidInstrumentedTest source set was decoupled from this tree by default (you can recouple it with a dependsOn call), but there was no way to remove the dependsOn relationship for the androidUnitTest source set. So this API provides the ability to configure both androidInsturmentedTest and androidUnitTest to belong to whichever source set tree makes sense for your code.Jeff Lockhart
05/25/2023, 6:16 PMandroidUnitTest source set? And how do your library users depend on your tests?
we want to allow users of our library to run tests on either JVM or Android as they see fitDo you mean consumers of your library being able to run their own tests as either JVM or Android instrumented or unit tests? Because they should be able to do this depending on the
jvm or android publications of your library, right?Jeff Lockhart
05/25/2023, 6:27 PMchrmelchior
05/25/2023, 6:31 PMandroid or jvm publications we publish. The multiplatform plugin selects the right one automatically and pure android projects use the -android artifact directly.
I suspect we need to do some gradle dependency substitution for pure android projects no matter what, but for multiplatform projects it would be nice if we could either release some artifact that androidUniTest would automatically pick or modify the gradle metadata some the jvm publication was chosen by androidUnitTest rather than the android publication.Jeff Lockhart
05/25/2023, 6:36 PMandroidUnitTest or are you just running commonTest tests?Jeff Lockhart
05/25/2023, 6:40 PMandroidUnitTest, what platform Gradle would select on in this case. KMP publishes attributes on the platform variants. But will gradle choose android or standard-jvm for the org.gradle.jvm.environment attribute? There's also the org.jetbrains.kotlin.platform.type attribute with jvm and androidJvm.chrmelchior
05/25/2023, 6:41 PMchrmelchior
05/25/2023, 6:42 PMchrmelchior
05/25/2023, 6:43 PMandroidUnitTests that only was available on Android. In that case they would go to the androidInstrumentedTest folderJeff Lockhart
05/25/2023, 6:47 PMjvm attribute variant, I'd expect you should be able to declare the base artifact:
dependencies {
implementation("lib")
}
And it would choose the -android variant for the main build and instrumented tests automatically, and then choose the -jvm variant for unit tests, if it does work this way.
You could manually declare the variant for the unit tests:
dependencies {
implementation("lib-android")
testImplementation("lib-jvm")
}
In this case, it's forcing both onto the classpath and it should exclude the variant that doesn't match the platform attribute. If that's jvm for Android unit tests, then it should work as expected, just not sure if that's the case or not.
(You should be able to do this similarly with multiplatform dependency declaration.)chrmelchior
05/25/2023, 6:49 PMchrmelchior
05/25/2023, 6:50 PMandroidUnitTest is a mix of both Android and JVMJeff Lockhart
05/25/2023, 6:51 PMJeff Lockhart
05/25/2023, 7:26 PMBut ideally we want to move to a world where all the common tests are actually in “commonTest” and then each platform has its own.
So there wouldn’t beThis sounds like you'd then be able to do what I described initially, removingthat only was available on Android. In that case they would go to theandroidUnitTestsfolderandroidInstrumentedTest
androidUnitTest from and adding androidInstrumentedTest to SourceSetTree.test.Jeff Lockhart
05/25/2023, 7:42 PMjvm variant's platform attribute to be android and the android variant's attribute jvm, specifically for the androidUniTest source set. But that would be pretty hacky.Jeff Lockhart
05/25/2023, 7:46 PMchrmelchior
05/25/2023, 7:53 PMJeff Lockhart
05/25/2023, 7:56 PMorg.gradle.jvm.environment and org.jetbrains.kotlin.platform.type attributes that a source set selects variants on.Jeff Lockhart
05/25/2023, 7:59 PMchrmelchior
05/26/2023, 8:08 AMconfigurations.all {
// Ensure that androidUnitTest uses the Realm JVM variant rather than Android.
if (name == "debugUnitTestRuntimeClasspath") {
resolutionStrategy.dependencySubstitution {
substitute(module("io.realm.kotlin:library-base:${Realm.version}")).using(
module("io.realm.kotlin:library-base-jvm:${Realm.version}")
)
substitute(module("io.realm.kotlin:cinterop:${Realm.version}")).using(
module("io.realm.kotlin:cinterop-jvm:${Realm.version}")
)
}
}
}
And that will work fine for our internal tests, but is going to be pretty annoying for our external users. I’ll try to ask in #gradle and see if they have a better idea. Thanks for the hints 🙏Jeff Lockhart
05/26/2023, 3:21 PMchrmelchior
05/26/2023, 3:36 PM