Kotlin Multiplatform Testing Part What?
What about loading in resources from a resource directory?
Ok, so what do we do a lot of in testing? We load a file, process it somehow, and check the results. Also, our program itself needs to be able to load resource files too. So I really thought this would be easy, and I learned something important about how the multiplatform thing works with actual
and expect
So what was the test that broke stuff?
@Test
fun `loads a file from the resources dir`() {
val text = this.javaClass.classLoader.getResource("/test.txt")
.shouldNotBeNull()
.readText()
.shouldNotBeNull()
.shouldBe("boo!")
}
This failed because javaClass wasn’t available in commonTest. It will link and run in desktopTest, which led me to another issue: where do resources go? The system can’t find it in the resources dir in the desktopTest dir:
Well for starters, resources are managed differently on different platforms, so naturally there isn’t one common way of loading a file from a resource directory.
Let us first remove the duplication and factor our test out. Each test has the same this.javaClass.classLoader.getResource(“/test.txt”)
, and if we use iOs, native, or javascript targets this won’t work. So lets factor it out:
class ResourceLoader {
fun readTextFromFile(path: String): String? {
TODO("Not yet implemented")
}
}
so how do we tell Kotlin Multiplatform that we want one class to do something different on each platform? We use expect
and actual.
We can define something in common with expect and then we have to define it with actual in all our targets. We can call it in the common code and then it gets replaced with the actual code in the particular target. So in the commonMain sourceset we will define our ResourceLoader:
expect class ResourceLoader {
fun readTextFromFile(path: String): String?
}
and then we put actual implementations in the sourceSets of the targets:
actual class ResourceLoader {
actual fun readTextFromFile(path: String): String? {
return this.javaClass.getResource(path)?.readText()
}
}
should suffice in any that have a classloader. So I put this in android and desktop, and a TODO in iOs. Now it all compiles - there is still some duplication between android and desktop. I don’t know how to remove this, so if anyone knows please let me know!
The second issue is in Kotlin Multiplatform, how do we make sure a particular directory ends up as a resource as far as our classloader is concerned? We will work on that tomorrow.