Skip to content

Commit fe925ba

Browse files
committed
📝 **Documentation : Amélioration du README avec des instructions de test**
Ce commit améliore le README en ajoutant des instructions détaillées sur la configuration et l'exécution de tests pour l'application Kotlin Multiplatform. Le README a été mis à jour avec des informations sur : - La configuration du projet pour les tests. - L'écriture de tests instrumentés pour Android. - L'utilisation de Robolectric et JUnit 5 pour les tests unitaires. - L'augmentation de la couverture du code avec Kover. En outre, un lien vers un exemple de projet a été ajouté pour fournir une référence concrète aux développeurs. Ces améliorations font du README un guide plus complet et plus utile pour les développeurs qui souhaitent tester leurs applications Kotlin Multiplatform.
1 parent 5a5b28b commit fe925ba

File tree

5 files changed

+121
-22
lines changed

5 files changed

+121
-22
lines changed

‎README.md

+105-17
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,114 @@
1-
This is a Kotlin Multiplatform project targeting Android, iOS, Web, Desktop.
1+
## Testing a Kotlin Multiplatform App with Compose and Robolectric
22

3-
* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
4-
It contains several subfolders:
5-
- `commonMain` is for code that’s common for all targets.
6-
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
7-
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
8-
`iosMain` would be the right folder for such calls.
3+
This guide explains how to set up unit tests for a Kotlin Multiplatform application using Compose and Robolectric.
94

10-
* `/iosApp` contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform,
11-
you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
5+
**Why this is important:**
126

7+
* **Shared code:** Kotlin Multiplatform lets you share code between Android, iOS, Desktop, and Web.
8+
* **Efficient testing:** Robolectric enables fast unit tests by simulating the Android environment on your development machine.
139

14-
Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html),
15-
[Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/#compose-multiplatform),
16-
[Kotlin/Wasm](https://kotl.in/wasm/)…
10+
**What you'll learn:**
1711

18-
We would appreciate your feedback on Compose/Web and Kotlin/Wasm in the public Slack channel [#compose-web](https://slack-chats.kotlinlang.org/c/compose-web).
19-
If you face any issues, please report them on [GitHub](https://github.com/JetBrains/compose-multiplatform/issues).
12+
* How to configure a Kotlin Multiplatform project for testing.
13+
* How to write instrumented tests that run on a real Android device or emulator.
14+
* How to write unit tests using Robolectric and JUnit 5.
15+
* How to increase code coverage with Kover.
2016

21-
You can open the web application by running the `:composeApp:wasmJsBrowserDevelopmentRun` Gradle task.
17+
**Steps:**
2218

19+
1. **Project Setup:**
2320

24-
https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-test.html
21+
* Create a `commonTest` directory in your `composeApp` module.
22+
* Add the following dependencies to your `build.gradle.kts`:
2523

26-
https://github.com/apter-tech/junit5-robolectric-extension
24+
```kotlin
25+
kotlin {
26+
sourceSets {
27+
commonTest.dependencies {
28+
implementation(kotlin("test"))
29+
implementation(compose.uiTest)
30+
}
31+
androidInstrumentedTest.dependencies {
32+
implementation(compose.uiTest)
33+
}
34+
}
35+
androidTarget {
36+
instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test)
37+
dependencies {
38+
debugImplementation(libs.androidx.ui.test.manifest)
39+
}
40+
}
41+
}
42+
android {
43+
defaultConfig {
44+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
45+
}
46+
}
47+
```
48+
49+
2. **Write a Simple Test:**
50+
51+
* Create a test file (e.g., `AppTest.kt`) in `commonTest`.
52+
* Write a test using `runComposeUiTest` to interact with a Compose component:
53+
54+
```kotlin
55+
class AppTest: UsingContext() {
56+
@Test
57+
fun myTest() = runComposeUiTest {
58+
setContent {
59+
MaterialTheme {
60+
App()
61+
}
62+
}
63+
onNodeWithText("Click me!").performClick()
64+
}
65+
}
66+
```
67+
68+
3. **Run Instrumented Test:**
69+
70+
* Launch an Android emulator.
71+
* Run the test: `./gradlew composeApp:connectedAndroidTest`
72+
73+
4. **Add Robolectric and JUnit 5:**
74+
75+
* Upgrade to Kotlin 2.1.0.
76+
* Add the Robolectric plugin and dependencies.
77+
* Apply the plugin in your `build.gradle.kts`.
78+
79+
5. **Create and Implement `UsingContext`:**
80+
81+
* Create an `expect` class named `UsingContext` in `commonTest`.
82+
* Implement the `actual` class for Android in `androidTest`, configuring Robolectric.
83+
* Implement empty `actual` classes for other platforms (iOS, Desktop, Web).
84+
85+
6. **Add an Activity to the Manifest:**
86+
87+
* Add an empty `ComponentActivity` to your `AndroidManifest.xml`.
88+
89+
7. **Run Robolectric Tests:**
90+
91+
* Run: `./gradlew composeApp:testDebugUnitTest`
92+
93+
8. **Exclude `UsingContext` from `check` Task:**
94+
95+
* Prevent JUnit5 from misinterpreting `UsingContext` as a test class:
96+
97+
```kotlin
98+
tasks.withType<Test>().configureEach {
99+
exclude("fr/pitdev/article/kmtest/utils/UsingContext.class")
100+
}
101+
```
102+
103+
* Run the check task: `./gradlew check`
104+
105+
**Bonus: Code Coverage with Kover**
106+
107+
1. Add Kover dependencies and plugin.
108+
2. Apply the plugin and configure Kover in your `build.gradle.kts`.
109+
3. Generate an HTML report: `gradlew koverHtmlReport`
110+
111+
**Learn More:**
112+
113+
* [Kover Repository](https://www.google.com/url?sa=E&source=gmail&q=https://github.com/Kotlin/kotlinx-kover)
114+
* Example Project [https://github.com/fpitpit/article-km-junit5-robolectric]

‎build.gradle.kts

+11
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,15 @@ plugins {
77
alias(libs.plugins.composeCompiler) apply false
88
alias(libs.plugins.kotlinMultiplatform) apply false
99
alias(libs.plugins.junit5.robolectric) apply false
10+
alias(libs.plugins.kover)
11+
}
12+
13+
dependencies {
14+
kover(project(":composeApp"))
15+
}
16+
17+
kover {
18+
merge {
19+
subprojects()
20+
}
1021
}

‎composeApp/src/androidUnitTest/kotlin/fr/pitdev/article/kmtest/utils/UsingContext.android.kt

-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@ import android.os.Build
44
import androidx.compose.runtime.Composable
55
import androidx.compose.runtime.CompositionLocalProvider
66
import androidx.compose.ui.platform.LocalInspectionMode
7-
import com.ibm.icu.impl.Assert
87
import org.jetbrains.compose.resources.ExperimentalResourceApi
98
import org.jetbrains.compose.resources.PreviewContextConfigurationEffect
109
import org.junit.jupiter.api.extension.ExtendWith
11-
import org.robolectric.TestLifecycleApplication
1210
import org.robolectric.annotation.Config
13-
import org.robolectric.shadows.ShadowApplicationPackageManager
1411
import org.robolectric.shadows.ShadowLog
1512
import tech.apter.junit.jupiter.robolectric.RobolectricExtension
1613
import kotlin.test.BeforeTest
17-
import kotlin.test.Test
1814

1915
@ExtendWith(RobolectricExtension::class)
2016
@Config(

‎composeApp/src/commonTest/kotlin/fr/pitdev/article/kmtest/AppTest.kt

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class AppTest: UsingContext() {
1010
@Test
1111
fun myTest() = runComposeUiTest {
1212
setContent {
13+
initPreviewContextConfiguration()
1314
MaterialTheme {
1415
App()
1516
}

‎gradle/libs.versions.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ kotlinx-coroutines = "1.9.0"
1818
uiTestManifest = "1.7.5"
1919
junit5-robolectric = "0.9.0"
2020

21+
kover = "0.9.0-RC"
22+
2123
[libraries]
2224
androidx-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "uiTestManifest" }
2325
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
@@ -40,4 +42,5 @@ androidLibrary = { id = "com.android.library", version.ref = "agp" }
4042
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
4143
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
4244
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
43-
junit5-robolectric = { id = "tech.apter.junit5.jupiter.robolectric-extension-gradle-plugin", version.ref = "junit5-robolectric" }
45+
junit5-robolectric = { id = "tech.apter.junit5.jupiter.robolectric-extension-gradle-plugin", version.ref = "junit5-robolectric" }
46+
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover"}

0 commit comments

Comments
 (0)