android-kotlin-testing
>
Works with
---
name: android-kotlin-testing
description: >
license: MIT
---
# Android Kotlin — Testing Module
Parent kit: [`../../SKILL.md`](../../SKILL.md) · Index: [`../../AGENTS.md`](../../AGENTS.md)
## Read First
| File | When |
|------|------|
| [`../../references/11-testing.md`](../../references/11-testing.md) | Turbine, fakes, Compose test tags |
| [`../../references/05-hilt-di.md`](../../references/05-hilt-di.md) | TestInstallIn modules |
| [`../../references/13-release-checklist.md`](../../references/13-release-checklist.md) | Pre-ship checklist |
## ViewModel Test Template
```kotlin
@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
```kotlin
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:
```bash
python3 scripts/validate_skills.py --strict
```More Mobile skills
animation-vocabulary
emilkowalski/skills
Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.
xcode-project-setup
firebase/agent-skills
Safely modifies Xcode projects (.pbxproj) to add Swift Packages and link files. Use this skill whenever an iOS project needs dependencies installed (e.g. Firebase, Alamofire).
cross-border-ecommerce
nexscope-ai/ecommerce-skills
Cross-border e-commerce expansion advisor. Scores target markets on 8 weighted dimensions (market size, ecommerce penetration, competition, regulatory complexity, logistics infrastructure, payment ecosystem, cultural distance, IP protection), compares 5 fulfillment models with cost and transit data, provides country-by-country tax/duty compliance guides (EU VAT/IOSS, UK VAT, US sales tax, CA GST, AU GST, JP consumption tax), maps local payment preferences by market, and builds a phased expansion roadmap. No API key required.

