Kotlin Testing Coroutines with kotlin-test

135 Views Asked by At

I have something of the following where I'm trying to test a class launches a coroutine and that coroutine does something properly in the thread. However I think don't have the right understanding on how context/dispatchers and scope work so this isn't working as expected.

class Janitor (
    private val sharedMap: MutableMap<Number, String>,
    private val delayMs: Long,
    private val dispatcher: CoroutineDispatcher = newSingleThreadContext("JanitorThread"),
) {
    private val janitorScope = CoroutineScope(dispatcher)
    
    fun cleanUp(key: Number) {
        janitorScope.launch(CoroutineName("Janitor Cleaning Up key:[$key]")) {
            println("Launching coroutine in JanitorThread to clean up $key after $delayMs")
            delay(delayMs)
            sharedMap.remove(key)
            println("Done removing $key from sharedMap after $delayMs")
        }
    }
}

class JanitorTest {
    @Test
    fun `janitor cleans up`() = runTest {
        val sharedMap = mutableMapOf<Number, String>()
        val janitor = Janitor(sharedMap, 1000L, StandardTestDispatcher())

        sharedMap[1] = "hello"
        sharedMap[2] = "world"
        janitor.cleanUp(1)
        
        advanceTimeBy(1000L)
        runCurrent()
        
        // Expect sharedMap size == 1
    }
}

The above test doesn't actually run the coroutine to completion and I'm unsure what I'm missing so any help would be greatly appreciated.

1

There are 1 best solutions below

0
On

You need to make sure the runTest function and Janitor are using the same dispatcher, otherwise your advanceTimeBy/runCurrent calls are not controlling the behavior of the coroutine launched inside Janitor.cleanUp.

This should work:

class JanitorTest {
    private val dispatcher = StandardTestDispatcher()

    @Test
    fun `janitor cleans up`() = runTest(dispatcher) {
        val sharedMap = mutableMapOf<Number, String>()
        val janitor = Janitor(sharedMap, 1000L, dispatcher)

        sharedMap[1] = "hello"
        sharedMap[2] = "world"
        janitor.cleanUp(1)

        advanceTimeBy(1000L)
        runCurrent()

        // Expect sharedMap size == 1
    }
}