Hey Kotlin Community! I am trying to write end to ...
# coroutines
e
Hey Kotlin Community! I am trying to write end to end testing where entry point is Android
ViewModel
and last point is
MockWebServer
from OkHTTP using
Coroutines
. In ViewModel I make a call using
viewModelScope.launch
. However when I try to run this code
Copy code
@get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @get:Rule
    var mainCoroutineRule = MainCoroutineRule()

    @Test
    fun reloadExpense() = runBlocking {
        viewModel.reloadExpense()
        assertThat(viewModel.state.value, CoreMatchers.instanceOf(LCE.Content::class.java))
    }
It does not wait for API request and just finishes the test. The MainCoroutine Rule is
Copy code
@ExperimentalCoroutinesApi
class MainCoroutineRule : TestWatcher(), TestCoroutineScope by TestCoroutineScope() {

    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(this.coroutineContext[ContinuationInterceptor] as CoroutineDispatcher)
    }

    override fun finished(description: Description?) {
        super.finished(description)
        Dispatchers.resetMain()
    }
}
I have tried using
runBlockingTest
,
runBlocking
and different types of rules. Nothing seems to work. Thank you in advance!
m
which dispatcher are you using to run the okhttp call? dispatchers.io? you need to replace that with testDispatcher as well (usually by injecting the dispatchers to the class that handles the okhttp call and replacing that dependency in tests)
e
@Michal Klimczak I am not specifying any particular dispatcher, so it is using default one (which I think is Main dispatcher). Do I still need to replace dispatcher or there is the other way?
m
I'm not really sure which dispatchers you're using here, because the rule that you specified looks exotic to me. In my tests I create an instance of TestDispatcher() and then use it both for main and for other dispatchers injected to the tested classes.
e
@Michal Klimczak I have tried that, but it does not work for some reason. I found that Retrofit creates it’s own thread to process network call. So the only way I got it working is by calling
runBlocking
on Retrofit
suspend
call
1
r
You have to inject a dispatcher into your
ViewModel
and replace it with the
TestCoroutineDispatcher
during tests else you will have have issues.