Kotlin Multiplatform Development Help

Testing Compose Multiplatform UI

UI testing in Compose Multiplatform is implemented using the same finders, assertions, actions, and matchers as the Jetpack Compose testing API. If you're not familiar with them, read the Jetpack Compose guide before you continue with this article.

How Compose Multiplatform testing is different from Jetpack Compose

Compose Multiplatform common test API does not rely on JUnit's TestRule class. Instead, you call the runComposeUiTest function and invoke the test functions on the ComposeUiTest receiver.

However, JUnit-based API is available for desktop targets.

Writing and running tests with Compose Multiplatform

First, add the source set for tests and the necessary dependencies to the module. Then, write and run the example test and try to customize it.

Create the test source set and add the testing library to dependencies

To provide concrete examples, the instructions on this page follow the project structure generated by the Kotlin Multiplatform wizard. If you are adding tests to an existing project, you may have to replace composeApp in paths and commands with the module name you are testing (shared, for example).

Create a common test source set and add the necessary dependencies:

  1. Create a directory for the common test source set: composeApp/src/commonTest/kotlin.

  2. In the composeApp/build.gradle.kts file, add the following dependencies:

    kotlin { //... sourceSets { val desktopTest by getting // Adds common test dependencies commonTest.dependencies { implementation(kotlin("test")) @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class) implementation(compose.uiTest) } // Adds the desktop test dependency desktopTest.dependencies { implementation(compose.desktop.currentOs) } } }
  3. If you need to run instrumented (emulator) tests for Android, amend your Gradle configuration further:

    1. Add the following code to the androidTarget {} block and follow IDE's suggestions to add missing imports:

      kotlin { //... androidTarget { @OptIn(ExperimentalKotlinGradlePluginApi::class) instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) //... } //... }
    2. Add the following code to the android.defaultConfig {} block:

      android { //... defaultConfig { //... testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } }
    3. Add the following code to the config top level:

      //https://developer.android.com/develop/ui/compose/testing#setup dependencies { androidTestImplementation("androidx.compose.ui:ui-test-junit4-android:1.6.8") debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.8") }

Now, you are ready to write and run common tests for the Compose Multiplatform UI.

Write and run common tests

In the composeApp/src/commonTest/kotlin directory, create a file named ExampleTest.kt and copy the following code into it:

import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.* import kotlin.test.Test class ExampleTest { @OptIn(ExperimentalTestApi::class) @Test fun myTest() = runComposeUiTest { // Declares a mock UI to demonstrate API calls // // Replace with your own declarations to test the code of your project setContent { var text by remember { mutableStateOf("Hello") } Text( text = text, modifier = Modifier.testTag("text") ) Button( onClick = { text = "Compose" }, modifier = Modifier.testTag("button") ) { Text("Click me") } } // Tests the declared UI with assertions and actions of the Compose Multiplatform testing API onNodeWithTag("text").assertTextEquals("Hello") onNodeWithTag("button").performClick() onNodeWithTag("text").assertTextEquals("Compose") } }

To run tests:

You have two options:

  • In Android Studio and Fleet, you can click the green run icon in the gutter next to the myTest() function, choose Run and the iOS target for the test.

  • Run the following command in the terminal:

    ./gradlew :composeApp:iosSimulatorArm64Test

Run this command in the terminal:

./gradlew :composeApp:connectedAndroidTest

Currently, you cannot run common Compose Multiplatform tests using android (local) test configurations, so gutter icons in Android Studio, for example, won't be helpful.

You have two options:

  • Click the green run icon in the gutter next to the myTest() function and choose Run | desktop.

  • Run the following command in the terminal:

    ./gradlew :composeApp:desktopTest

Run this command in the terminal:

./gradlew :composeApp:wasmJsTest

Running JUnit-based tests for desktop targets

To provide concrete examples, the instructions on this page follow the project structure generated by the Kotlin Multiplatform wizard. If you are adding tests to an existing project, you may have to replace composeApp in paths and commands with the module name you are testing (shared, for example).

Create the test source set and add the necessary dependencies:

  1. Create a directory for tests: composeApp/src/desktopTest/kotlin.

  2. In the composeApp/build.gradle.kts file, add the following dependencies:

    kotlin { //... sourceSets { //... val desktopTest by getting { dependencies { implementation(compose.desktop.uiTestJUnit4) implementation(compose.desktop.currentOs) } } } }
  3. Create a test file called ExampleTest.kt and copy the following code into it:

    import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.test.* import androidx.compose.ui.platform.testTag import androidx.compose.ui.test.junit4.createComposeRule import org.junit.Rule import org.junit.Test class ExampleTest { @get:Rule val rule = createComposeRule() @Test fun myTest(){ // Declares a mock UI to demonstrate API calls // // Replace with your own declarations to test the code in your project rule.setContent { var text by remember { mutableStateOf("Hello") } Text( text = text, modifier = Modifier.testTag("text") ) Button( onClick = { text = "Compose" }, modifier = Modifier.testTag("button") ) { Text("Click me") } } // Tests the declared UI with assertions and actions of the JUnit-based testing API rule.onNodeWithTag("text").assertTextEquals("Hello") rule.onNodeWithTag("button").performClick() rule.onNodeWithTag("text").assertTextEquals("Compose") } }
  4. To run the test, click the run icon in the gutter next to the myTest() function or run the following command in the terminal:

    ./gradlew desktopTest

What's next

Now that you got the hang of Compose Multiplatform UI testing, you may want to check out more testing-related resources:

Last modified: 25 September 2024