Testing (ViewModel & Compose UI)
Coroutine Tests & Compose Test Rule
Tests lock in behavior. Unit-test `ViewModel` logic with a test dispatcher, and assert your UI with the Compose testing rule using semantics (no Espresso view-matching).
๐ Explanation
`runTest` runs coroutines on a virtual clock, so `delay` is skipped and assertions see the final state deterministically. For UI, `createComposeRule()` hosts a Composable in isolation; you query the semantics tree with finders like `onNodeWithText`, drive interactions with `performClick()`, and assert with `assertIsDisplayed()` โ fast, reliable tests with no emulator-specific view matching.
Note: Code execution is not available for Android/Kotlin in the browser. Use Android Studio to run and test the app.
import androidx.compose.ui.test.*import androidx.compose.ui.test.junit4.createComposeRuleimport kotlinx.coroutines.test.runTestimport org.junit.Assert.assertEqualsimport org.junit.Ruleimport org.junit.Test// 1. Unit test a ViewModel with a virtual-time dispatcherclass CounterViewModelTest {@Testfun increment_updatesState() = runTest {val vm = CounterViewModel()vm.increment()// runTest skips real delays and drains pending coroutinesassertEquals(1, vm.state.value.count)}}// 2. UI test a Composable against its semantics treeclass GreetingTest {@get:Rule val composeRule = createComposeRule()@Testfun button_click_incrementsLabel() {composeRule.setContent { CounterScreen() }composeRule.onNodeWithText("Clicked 0 times").assertIsDisplayed()composeRule.onNodeWithText("Clicked 0 times").performClick()composeRule.onNodeWithText("Clicked 1 times").assertIsDisplayed()}}