calidion
02/04/2025, 7:16 PMMichael Paus
02/04/2025, 7:20 PMcalidion
02/04/2025, 7:25 PMcalidion
02/04/2025, 7:49 PMMichael Paus
02/04/2025, 10:28 PMcalidion
02/04/2025, 10:50 PMcalidion
02/04/2025, 10:50 PMMoussa
02/05/2025, 10:12 AMcommonMain
won't be able to have a dependency on jvm
only libs and the same goes for commonTest
.
If you want to write some test cases that are only available for the jvm
target. You can write them in jvmTest
and if you want to have access to specific libs that are only available on jvm
you can import these libs in gradle for jvmTest
source set. This way, in your jvmTest
, you would have access to all code written in commonMain
and libs that are only available in jvm
.
Hope that answer your questions!calidion
02/05/2025, 1:36 PMMoussa
02/05/2025, 2:46 PMMy test code is prepared for commonMain, why should I write tests in jvmTestBecause you want to use
jvm
dependencies to test your code as per this
can't test my commonMain with jvm packages.Am I misunderstanding your question?!
calidion
02/05/2025, 3:22 PMMoussa
02/05/2025, 3:24 PMcalidion
02/05/2025, 3:24 PMcalidion
02/05/2025, 3:26 PMcalidion
02/05/2025, 3:27 PMcalidion
02/05/2025, 3:27 PMcalidion
02/05/2025, 3:28 PMcalidion
02/05/2025, 3:29 PMcalidion
02/05/2025, 3:30 PMMoussa
02/05/2025, 3:34 PMJaCoCo
reports like we would do in jvm
or android
you can check this configuration from kotlinx-kover documentation https://kotlin.github.io/kotlinx-kover/gradle-plugin/#using-jacoco
• commonMain
is where you can write Kotlin code that will be shared among all targets that you have already added in your Gradle file. If you wrote a class in it, it will automatically be available for all targets. But, if you need different implementation per platform (something like an interface and that interface implementation is implemented differently for each target) then you can use expect/actual
feature of the KMP https://kotlinlang.org/docs/multiplatform-expect-actual.htmlMoussa
02/05/2025, 3:36 PMMoussa
02/05/2025, 3:37 PMcalidion
02/05/2025, 3:48 PMcalidion
02/05/2025, 3:50 PMcalidion
02/05/2025, 3:51 PMcalidion
02/05/2025, 3:52 PMMoussa
02/05/2025, 4:09 PMcommonMain
interface Animal {
fun speak(): String
}
class Cat : Animal {
override fun speak(): String {
return "Newo Newo"
}
}
class Dog : Animal {
override fun speak(): String {
return "Hao Hao"
}
}
You won't be able to test the Animal
interface. But you will be able to test the classes that are implement it, in this case, it would be Cat
and Dog
which will use the interface which will be added to the coverage report as being used.
The other option, which is using expect/actual
, example
// commanMain
interface Animal {
fun speak(): String
}
expect class Cat : Animal // This means that I your need to implement it in all supported targets (in this example, JVM, iOS)
// jvmMain
actual class Cat : Animal {
override fun speak(): String {
return "Newo Newo From JVM"
}
}
// iosMain
actual class Cat : Animal {
override fun speak(): String {
return "Newo Newo From iOS"
}
}
Then you can add your tests in commonTest
like this
expect class CatTests {
@Test
fun `test speak method`()
}
Then you go and implement the custom tests of the CatTests
per platform like we did with implementation of the Cat
class
In jvmMain
actual class CatTests {
@Test
fun `test speak method`() {
assertEquals("Newo Newo From JVM", Cat().speak())
}
}
In iosMain
actual class CatTests {
@Test
fun `test speak method`() {
assertEquals("Newo Newo From iOS", Cat().speak())
}
}
calidion
02/05/2025, 4:18 PMinterface In {
fun api()
}
fun useInterface(i: In) {
i.api()
}
Moussa
02/05/2025, 4:22 PMclass Tests {
private val inImpl: In = object : In {
override fun api() {
// implement the logic you want here for testing purposes
}
}
@Test
fun `test useInterface method`() {
useInterface(inImpl)
}
}
calidion
02/05/2025, 4:29 PMMoussa
02/05/2025, 4:30 PMcalidion
02/05/2025, 4:31 PMMoussa
02/05/2025, 4:35 PMcalidion
02/05/2025, 5:02 PMcalidion
02/05/2025, 5:02 PMcalidion
02/05/2025, 5:03 PMcalidion
02/05/2025, 5:03 PMMoussa
02/06/2025, 6:32 AMiosMain
, jvmMain
, or androidMain
then you implement your tests in two ways.
The first way is to implement unit tests for each of them in their correct folder. Let's take your shared code as an example
In commanMain
interface In {
fun api()
}
fun useInterface(i: In) {
i.api()
}
in jvmMain
class Moussa : In {
override fun api() {
// Implement your logic here
}
}
Then you have to write test cases in jvmTests
to test that specific logic and have coverage report for the part implemented in jvmMain
OR, you can use expect/actual
You would have in commonTest
expect class InTests {
@Test
fun `test api method per platform`()
}
Then you would go and implement that class and it's method in the test module of each platform. This way, make your code testable from common
and allow access to your different implementation per platform and allow for the test coverage for all of them
In jvmTest
you would have
actual class InTests {
@Test
actual fun `test api method per platform`() {
// Implement your unit test here
}
}