androidengineers.Book a session
โ† All interview questions
TestingIntermediate3 min

A debounced search test fails randomly in CI. How would you remove real-time waiting?

Answer

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.

Example

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.

Follow-up to practise

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.

Reference

Android Developers: Testing Kotlin coroutines

Mark this when you can explain the answer in your own words.

Share & Help Others

Help fellow developers prepare for interviews

Sharing helps the Android community grow ๐Ÿ’š

Keep practising