mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 21:53:28 +08:00
3.3 KiB
3.3 KiB
paths
| paths | ||
|---|---|---|
|
Kotlin Testing
This file extends common/testing.md with Kotlin and Android/KMP-specific content.
Test Framework
- kotlin.test for multiplatform (KMP) —
@Test,assertEquals,assertTrue - JUnit 4/5 for Android-specific tests
- Turbine for testing Flows and StateFlow
- kotlinx-coroutines-test for coroutine testing (
runTest,TestDispatcher)
ViewModel Testing with Turbine
@Test
fun `loading state emitted then data`() = runTest {
val repo = FakeItemRepository()
repo.addItem(testItem)
val viewModel = ItemListViewModel(GetItemsUseCase(repo))
viewModel.state.test {
assertEquals(ItemListState(), awaitItem()) // initial state
viewModel.onEvent(ItemListEvent.Load)
assertTrue(awaitItem().isLoading) // loading
assertEquals(listOf(testItem), awaitItem().items) // loaded
}
}
Fakes Over Mocks
Prefer hand-written fakes over mocking frameworks:
class FakeItemRepository : ItemRepository {
private val items = mutableListOf<Item>()
var fetchError: Throwable? = null
override suspend fun getAll(): Result<List<Item>> {
fetchError?.let { return Result.failure(it) }
return Result.success(items.toList())
}
override fun observeAll(): Flow<List<Item>> = flowOf(items.toList())
fun addItem(item: Item) { items.add(item) }
}
Coroutine Testing
@Test
fun `parallel operations complete`() = runTest {
val repo = FakeRepository()
val result = loadDashboard(repo)
advanceUntilIdle()
assertNotNull(result.items)
assertNotNull(result.stats)
}
Use runTest — it auto-advances virtual time and provides TestScope.
Ktor MockEngine
val mockEngine = MockEngine { request ->
when (request.url.encodedPath) {
"/api/items" -> respond(
content = Json.encodeToString(testItems),
headers = headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString())
)
else -> respondError(HttpStatusCode.NotFound)
}
}
val client = HttpClient(mockEngine) {
install(ContentNegotiation) { json() }
}
Room/SQLDelight Testing
- Room: Use
Room.inMemoryDatabaseBuilder()for in-memory testing - SQLDelight: Use
JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)for JVM tests
@Test
fun `insert and query items`() = runTest {
val driver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
Database.Schema.create(driver)
val db = Database(driver)
db.itemQueries.insert("1", "Sample Item", "description")
val items = db.itemQueries.getAll().executeAsList()
assertEquals(1, items.size)
}
Test Naming
Use backtick-quoted descriptive names:
@Test
fun `search with empty query returns all items`() = runTest { }
@Test
fun `delete item emits updated list without deleted item`() = runTest { }
Test Organization
src/
├── commonTest/kotlin/ # Shared tests (ViewModel, UseCase, Repository)
├── androidUnitTest/kotlin/ # Android unit tests (JUnit)
├── androidInstrumentedTest/kotlin/ # Instrumented tests (Room, UI)
└── iosTest/kotlin/ # iOS-specific tests
Minimum test coverage: ViewModel + UseCase for every feature.