Dmitry
01/03/2023, 1:53 PMViewModel
classes with the recent coroutines-test API and it doesn't work as expected.
@Test
fun `when balanceOf() is called with existing parameter model state is updated with correct value`() = runTest {
Dispatchers.setMain(StandardTestDispatcher())
fakeWalletRepository.setPositiveBalanceOfResponse()
assertThat("Model balance is not default", subj.uiState.value.wallet.getBalance().toInt() == 0)
assertThat("Errors queue is not empty", subj.uiState.value.errors.isEmpty())
assertThat("State is not default", subj.uiState.value.status == Status.NONE)
subj.balanceOf("0x6f1d841afce211dAead45e6109895c20f8ee92f0")
advanceUntilIdle()
assertThat("Model balance is not updated with correct value", subj.uiState.value.wallet.getBalance().toLong() == 42L)
assertThat("Errors queue is not empty", subj.uiState.value.errors.isEmpty())
assertThat("State is not set as BALANCE", subj.uiState.value.status == Status.BALANCE)
}
The issue is not working stably - usually it fails, under debugger usually it passes.
Based on my understanding StandartTestDispatcher
shouldn't run coroutines until advanceUntilIdle
call when UnconfinedTestDispatcher
run them immediately. advanceUntilIdle
should wait until all coroutines are finished, but it seems there is a race condition in the next assertThat()
call which causes ambiguity in the behaviour of my test case.
advanceUntilIdle
should guarantee all coroutines end their work. Does it mean race condition occurs somewhere under .collect{}
or state.update {}
calls? (In my understanding advanceUntilIdle
should wait end of their execution too)
fun balanceOf(owner: String) {
logger.d("[start] balanceOf()")
viewModelScope.launch {
repository.balanceOf(owner)
.flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
.collect { value ->
logger.d("collect get balance result")
processBalanceOfResponse(value)
}
}
logger.d("[end] balanceOf()")
}
.flowOn()
It have to replaced explicitly in addition to the code above.