Replace guessed wall-clock sleeps with a coroutine test scheduler. Inject dispatchers where needed so the code under test actually runs on that scheduler. A hard-coded dispatcher can escape virtual-time control.
This self-contained Flow test checks that a newer query replaces an older one:
@OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)
@Test
fun searchWaitsForQuietPeriod() = runTest {
val queries = MutableSharedFlow<String>()
val requested = mutableListOf<String>()
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
queries.debounce(300).collect { requested += it }
}
queries.emit("kot")
runCurrent()
advanceTimeBy(200)
queries.emit("kotlin")
runCurrent()
advanceTimeBy(299)
assertEquals(emptyList<String>(), requested)
advanceTimeBy(1)
runCurrent()
assertEquals(listOf("kotlin"), requested)
}
The collector starts before emission. runCurrent() executes work scheduled at the current virtual time, including the exact deadline after advancing time. backgroundScope is cancelled at test completion.
Does this prove stale network responses cannot overwrite results? No. Add a separate test with controllable fake requests: let an older response arrive after a newer one and assert the newest query remains visible. Debouncing and response ordering solve different problems.
Mark this when you can explain the answer in your own words.
Help fellow developers prepare for interviews
Sharing helps the Android community grow ๐