Testing MutableStateFlow without flakiness
April 2021
- We need the observable itself:
private val _countdown = MutableStateFlow(0)
val countdown = _countdown.asStateFlow()
2. Now we need some collector, that we’ll need to use for testing:
val scope = CoroutineScope(Job() + Dispatchers.Main)
val countdownObserver = mock<FlowCollector<Int>>()
scope?.launch { countdown.collect(countdownObserver) }
3. Let’s test:
_countdown.value = 0
verify(countdownObserver).emit(0)
_countdown.value = 0
verify(countdownObserver).emit(0)
The complete snippet.
- It fails and it’s the correct behaviour.
- Dispatchers.Main is the must! Dispatchers.IO will give you a lot of flakiness!
package com.visa.mobile.feature.payments.usecase
import com.nhaarman.mockitokotlin2.clearInvocations
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.visa.mobile.common.TestCoroutineRule
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Rule
import org.junit.Test
@InternalCoroutinesApi
@ExperimentalCoroutinesApi
class MutableStateFlowTest {
@get:Rule
var coroutineRule = TestCoroutineRule()
@Test
fun `test MutableStateFlow`() = coroutineRule.runBlockingTest {
val countdown = MutableStateFlow(0)
val countdownObserver = mock<FlowCollector<Int>>()
val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch { countdown.collect(countdownObserver) }
countdown.value = 0; verify(countdownObserver).emit(0)
clearInvocations(countdownObserver)
countdown.value = 0; verify(countdownObserver).emit(0)
scope.cancel()
}
}
Leave a Reply