Tim Malseed
12/30/2021, 11:08 AMrunBlockingTest()
, this delay is skipped, so this function completes immediately, and the StateFlow essentially bypasses the value I’m trying to test.
It’s worth mentioning, I’m using CashApp/Turbine as well.Tim Malseed
12/30/2021, 11:08 AMsealed class ViewState {
object None : ViewState()
object Loading : ViewState()
object Some : ViewState()
}
class Foo {
val viewState = MutableStateFlow<ViewState>(ViewState.None)
fun updateViewState() {
viewState.value = ViewState.Loading
viewState.value = someLongRunningOperation()
}
private suspend fun somePotentiallyLongRunningOperation(): ViewState {
delay(5000)
return ViewState.Some
}
}
@Test
fun myTest() = runBlockingTest {
foo.viewState.test {
foo.updateViewState()
assertThat(awaitItem()).isInstanceOf(ViewState.Loading::class.java) // Fails. ViewState is ViewState.Some
cancelAndConsumeRemainingEvents()
}
}
Eugen Martynov
12/30/2021, 2:03 PMEugen Martynov
12/30/2021, 2:03 PMMartin Rajniak
12/30/2021, 7:06 PMCalls toSo if I understand correctly if you use,withContext(<http://Dispatchers.IO|Dispatchers.IO>)
,andwithContext(Dispatchers.Default)
are common in coroutines-based code bases. Unfortunately, just executing code in a test will not lead to these dispatchers using the virtual time source, so delays will not be skipped in them.withContext(Dispatchers.Main)
withContext
and don't replace provider for the TestDispatcher
then delay won't be skipped.
There has to be other way - just that I noticed this so wanted to share 🙂Martin Rajniak
12/30/2021, 7:10 PMrunBlockingTest
at all? 🤔
You might just want to create custom CoroutineScope
as you would in production and run the test with that.
(just thinking aloud - not sure if true)Nick Allen
12/30/2021, 8:27 PM@Test
fun myTest() = runBlockingTest {
launch {
foo.updateViewState()
}
runCurrent()
assertEquals(ViewState.Loading, fot.viewState)
}
}
Nick Allen
12/30/2021, 8:30 PMNick Allen
12/30/2021, 8:33 PM@Test
fun myTest() = runBlockingTest {
launch {
for.updateViewState()
}
runCurrent()
foo.viewState.test {
assertThat(awaitItem()).isInstanceOf(ViewState.Loading::class.java) // Fails. ViewState is ViewState.Some
cancelAndConsumeRemainingEvents()
}
}
Tim Malseed
12/30/2021, 10:17 PMTim Malseed
12/30/2021, 10:36 PMTim Malseed
12/30/2021, 10:45 PMTim Malseed
12/30/2021, 11:29 PMrunTest()
does seem to solve most of my problems, and revealed a few new ones that make me wonder how the tests ever passed at all!