Use this skill when the task is primarily about Android test strategy, JUnit, Espresso, Robolectric, Compose testing, test reliability, or verification design.
Use this skill for verification strategy and test reliability on Android.
ComposeTestRuletest/ for unit, androidTest/ for instrumented)TestDispatcher, )runTestrunTest and TestDispatcher for coroutine-based unit tests.loginWithInvalidEmail_showsError over testLogin1.runTest with TestScope for deterministic coroutine testingComposeTestRule with semantic matchers for Compose UI tests@TestInstallIn for swapping production modules in testsrunBlocking instead of runTest, hiding timing issuescreateComposeRule(), onNodeWithText, performClick (Compose 1.0+)runTest, TestDispatcher, advanceUntilIdle (kotlinx-coroutines-test 1.6+)@Test
fun `fetchUser returns profile on success`() = runTest {
val fakeRepo = FakeUserRepository(user = testUser)
val viewModel = ProfileViewModel(fakeRepo)
viewModel.loadUser("123")
advanceUntilIdle()
assertEquals(ProfileUiState.Success(testUser), viewModel.uiState.value)
}
// Wrong: runBlocking hides dispatcher issues, Thread.sleep is timing-dependent
@Test
fun `fetchUser returns profile`() = runBlocking {
val viewModel = ProfileViewModel(RealUserRepository()) // real dependency
viewModel.loadUser("123")
Thread.sleep(2000) // arbitrary delay
assertNotNull(viewModel.uiState.value)
}
@get:Rule val composeRule = createComposeRule()
@Test
fun `login button is disabled when email is empty`() {
composeRule.setContent { LoginScreen(viewModel = fakeViewModel) }
composeRule.onNodeWithTag("loginButton").assertIsNotEnabled()
}
// Wrong: asserts on text content that changes with localization
@Test
fun `login works`() {
composeRule.setContent { LoginScreen() }
composeRule.onNodeWithText("Log In").performClick()
Thread.sleep(3000) // arbitrary wait
}