一键导入
mobiai-android-testing
Use when writing or running tests in an Android project — unit tests, UI tests, choosing the right framework and patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when writing or running tests in an Android project — unit tests, UI tests, choosing the right framework and patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
first community fixture skill
second community fixture skill
third community fixture skill
Actualiza el binario `mobiai` a la última versión publicada en GitHub Releases. Usá esta skill cuando el banner de SessionStart muestre "MobiAI update available" o cuando el usuario pida explícitamente actualizar MobiAI.
Use when starting any conversation — establishes how to find and invoke MobiAI skills, requiring `Skill` tool invocation before ANY response including clarifying questions, git/file reads, or code exploration
test fixture
| name | mobiai-android-testing |
| description | Use when writing or running tests in an Android project — unit tests, UI tests, choosing the right framework and patterns. |
| license | MIT |
| compatibility | ["claude-code","cursor","copilot","codex"] |
| platforms | ["android"] |
Comprehensive guide to writing and running tests in Android projects.
| Type | Location | Framework | Speed | Uses Device |
|---|---|---|---|---|
| Unit | src/test/ | JUnit + MockK | Fast | No |
| Integration | src/test/ | JUnit + Robolectric | Medium | No (simulated) |
| UI / Instrumented | src/androidTest/ | Espresso / Compose Testing | Slow | Yes |
// build.gradle.kts
dependencies {
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.13.12")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
testImplementation("app.cash.turbine:turbine:1.2.0") // For Flow testing
}
Mirror the source path:
app/src/main/java/com/example/feature/MyViewModel.ktapp/src/test/java/com/example/feature/MyViewModelTest.ktclass MyViewModelTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()
private val repository: MyRepository = mockk()
private lateinit var viewModel: MyViewModel
@Before
fun setUp() {
viewModel = MyViewModel(repository)
}
@Test
fun `loadData sets state to Success when repository returns data`() = runTest {
// Given
val expected = listOf(Item("1", "Test"))
coEvery { repository.getData() } returns expected
// When
viewModel.loadData()
// Then
assertEquals(UiState.Success(expected), viewModel.state.value)
coVerify(exactly = 1) { repository.getData() }
}
@Test
fun `loadData sets state to Error when repository throws`() = runTest {
// Given
coEvery { repository.getData() } throws IOException("Network error")
// When
viewModel.loadData()
// Then
assertTrue(viewModel.state.value is UiState.Error)
}
}
class MainDispatcherRule(
private val dispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {
override fun starting(description: Description) {
Dispatchers.setMain(dispatcher)
}
override fun finished(description: Description) {
Dispatchers.resetMain()
}
}
// Create mock
val repo: Repository = mockk()
val repo: Repository = mockk(relaxed = true) // Returns defaults for unconfigured calls
// Stub behavior
every { repo.getData() } returns listOf(item)
coEvery { repo.fetchData() } returns result // For suspend functions
every { repo.getData() } throws IOException()
every { repo.save(any()) } just runs // Void functions
// Verify
verify { repo.getData() }
verify(exactly = 1) { repo.save(any()) }
coVerify { repo.fetchData() }
verify(exactly = 0) { repo.delete(any()) } // Never called
// Capture arguments
val slot = slot<String>()
every { repo.search(capture(slot)) } returns emptyList()
// After call: slot.captured == "search term"
// Mock objects/companions
mockkObject(MySingleton)
every { MySingleton.instance } returns mockk()
@Test
fun `events flow emits navigation event`() = runTest {
viewModel.events.test {
viewModel.onSubmitClicked()
assertEquals(Event.NavigateToSuccess, awaitItem())
cancelAndConsumeRemainingEvents()
}
}
dependencies {
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
class MyScreenTest {
@get:Rule
val composeRule = createComposeRule()
@Test
fun submitButton_isDisabled_whenFieldIsEmpty() {
composeRule.setContent {
MyScreen(state = MyState(text = ""))
}
composeRule.onNodeWithText("Submit").assertIsNotEnabled()
}
@Test
fun errorMessage_isDisplayed_whenStateIsError() {
composeRule.setContent {
MyScreen(state = MyState(error = "Something went wrong"))
}
composeRule.onNodeWithText("Something went wrong").assertIsDisplayed()
}
}
@Test
fun clickSubmit_showsConfirmation() {
onView(withId(R.id.btn_submit)).perform(click())
onView(withText("Confirmed")).check(matches(isDisplayed()))
}
# All unit tests
./gradlew testDebugUnitTest
# Specific flavor
./gradlew test<Flavor>DebugUnitTest
# Single test class
./gradlew testDebugUnitTest --tests "com.example.MyViewModelTest"
# Single test method
./gradlew testDebugUnitTest --tests "com.example.MyViewModelTest.loadData sets state to Success*"
# Instrumented tests (requires device/emulator)
./gradlew connectedDebugAndroidTest
@Test
fun `invoke returns transformed data`() = runTest {
coEvery { repository.getItems() } returns rawItems
val result = useCase()
assertEquals(expectedTransformed, result)
}
// Use in-memory database for tests
val db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
val dao = db.myDao()
@Test
fun `toEntity maps all fields correctly`() {
val dto = MyDto(id = "1", name = "Test", value = 42.0)
val entity = dto.toEntity()
assertEquals("1", entity.id)
assertEquals("Test", entity.name)
assertEquals(42.0, entity.value, 0.001)
}
@FlakyTest or increase timeoutsAdd to src/test/resources/mockk-extensions/io.mockk.ifc:
io.mockk.classmocking.enabled=true
Use advanceUntilIdle() or runCurrent() in runTest blocks.