Been looking at the new test helpers such as `runB...
# coroutines
m
Been looking at the new test helpers such as
runBlockingTest
,
TestCoroutineDispatcher
,
TestCoroutineScope
, etc. They look promising, however I haven't been able to figure out a way to stub a dependency's
suspend
function using
mockito-kotlin
such that it suspends indefinitely. The goal is to test scenarios within my Android
ViewModel
where
onCleared()
is called before a
suspend
function returns a result. Basically something like:
Copy code
private fun givenStatusNeverReceived() = runBlocking {
    // loadStatus() is a suspend function
    given(repository.loadStatus()).willAnswer {
        // suspend indefinitely
    }
}
l
Use MockK, it supports coroutines
👍 2
m
Been meaning to explore MockK for some time. Our entire codebase has been using
mockito-kotlin
with a heavy focus on the BDDMockito APIs. I was hoping to maintain consistency moving forward, however with the recent introduction of coroutines in our codebase (we've been using RxJava heavily), it looks like
mockito-kotlin
is starting to show its limitations.
l
I'd recommend to just try it at first. Also, I think you can have them side by side.
m
Played around with MockK for a bit and it took some getting used to. I like how strict it is by default though. However, I do miss the style of BDDMockito. But MockK's
coEvery
,
coAnswer
,
etc.
APIs make it quite easy to mock/stub
suspend
functions.
After playing around with it, I then got a few more ideas with
mockito-kotlin
and got something working, but it looks rather ugly IMO. Basically it's something like:
Copy code
private val deferredStatus = CompletableDeferred<Status>()

...

private fun TestCoroutineScope.whileAwaitingStatus() {
    given(repository.loadStatus()).willAnswer {
        var result: Status? = null
        runBlockingTest {
            result = deferredStatus.await()
        }
        return result!!
    }
}
However, even if you choose to not set a value for the
CompletableDeferred
, you have to make sure to call
cancel()
on it otherwise
runBlockingTest
throws an exception indicating that there was still an active
Job
running.