SuperAPI AI Directory

android-kotlin-testing

Testing & quality

View repository

Updated 10-15 22:11

About this skill

Android Kotlin — Testing Module

Parent kit: ../../SKILL.md · Index: ../../AGENTS.md

Read First

File When
../../references/11-testing.md Turbine, fakes, Compose test tags
../../references/05-hilt-di.md TestInstallIn modules
../../references/13-release-checklist.md Pre-ship checklist

ViewModel Test Template

@OptIn(ExperimentalCoroutinesApi::class)
class FeatureViewModelTest {
@get:Rule
val mainDispatcherRule = MainDispatcherRule()

private val fakeRepo = FakeFeatureRepository()
private lateinit var viewModel: FeatureViewModel

@Before
fun setup() {
    viewModel = FeatureViewModel(fakeRepo)
}

@Test
fun `refresh success clears loading`() = runTest {
    fakeRepo.syncResult = Result.success(Unit)

    viewModel.onEvent(FeatureUiEvent.Refresh)

    viewModel.state.test {
        skipItems(1)
        val loading = awaitItem()
        assertTrue(loading.isLoading)
        val done = awaitItem()
        assertFalse(done.isLoading)
        assertNull(done.error)
    }
}

}


## Fake Over Mock

```kotlin
class FakeFeatureRepository : FeatureRepository {
    var syncResult: Result<Unit> = Result.success(Unit)
    private val items = MutableStateFlow<List<Feature>>(emptyList())

    override fun observeItems(): Flow<List<Feature>> = items
    override suspend fun sync(): Result<Unit> = syncResult
}

Prefer fakes implementing real interfaces — tests behavior, not interaction order.

Compose UI Test

class FeatureScreenTest {
    @get:Rule
    val composeRule = createComposeRule()

    @Test
    fun showsEmptyState() {
        composeRule.setContent {
            AppTheme {
                FeatureContent(
                    state = FeatureUiState(items = emptyList()),
                    onEvent = {}
                )
            }
        }
        composeRule.onNodeWithTag("feature_empty").assertIsDisplayed()
    }
}

Test stateless FeatureContent, not ViewModel-integrated screen.

What to Test vs Skip

Always test Usually skip
ViewModel state transitions Room generated SQL
Repository mappers Hilt graph wiring (compile-time)
Error paths (Result.failure) Pixel-perfect screenshots
Critical user flows (instrumented) Third-party SDK internals

CI Gate

Repo skill validation must pass before merge:

python3 scripts/validate_skills.py --strict