I'm using coroutines for the first time and I'm having troubles testing my work on a ViewModel
.
The test fails with
Wanted but not invoked:
observer.onChanged(<Capturing argument>);
The test is the following:
val androidVersioningMock: Versioning.AndroidVersioning = mock {
on { required } doAnswer { "3.3.6" }
}
val versioningMock: Versioning = mock {
on { android } doAnswer { androidVersioningMock }
}
whenever(networkManager.getAppVersionAsync()).thenReturn(GlobalScope.async { versioningMock })
runBlocking {
updateVersionModel =
UpdateViewModel(application, coroutineDispatcherProvider).apply {
updateLiveData.observeForever(stateObserver)
}
verify(stateObserver).onChanged(stateCaptor.capture())
assertTrue(stateCaptor.lastValue is UpdateState.NoUpdate)
assertEquals(UpdateState.NoUpdate, stateCaptor.lastValue)
}
I have mocked the coroutineDispatcherProvider
with
@ExperimentalCoroutinesApi
override val coroutineDispatcherProvider = mock<CoroutineDispatcherProvider> {
on { main } doAnswer { TestCoroutineContext() }
on { io } doAnswer { TestCoroutineContext() }
}
And in my ViewModel, the method that fails is
private suspend fun getUpdateVersion(): Versioning =
withContext(coroutineDispatcherProvider.io) {
networkManager.getAppVersionAsync().await()
}
which is executed like :
launch {
val versioningModel = getUpdateVersion()
...
}
Am I not mocking something or not doing something? Thanks in advance!
The TestCoroutineContext
dispatcher is useful to handle timing within tests, but you want to run asynchronous calls synchronously. You should be able to achieve this with the Unconfined
dispatcher.