You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Version Mockito 3.2.4
JDK 8
Ubuntu 18.04
Test run in Android Studio IDE 3.5.3
Using the eq() argument matcher when calling any Kotlin suspend function will always match the first (original) call, but will fail to match any continuation resume calls made by the Kotlin coroutine framework.
However, if you change the eq() to any() or anyInt() (if your function argument is an Int value), then the argument matcher will work for the original call and all subsequent continuation resume calls.
I realize that there is an extra hidden parameter but it seems to me that if eq() succeeds in the original test call, it should also succeed for the continuation resume calls.
The following 2 test in the test class provided below will produce TooFewActualInvocations for the 2nd test:
Test output:
org.mockito.exceptions.verification.TooFewActualInvocations:
foobar.foobar(4);
Wanted 5 times:
-> at Example.$Foobar.foobar(Example.kt:15)
But was 1 time:
-> at Example$callFoobar$2$job$1.invokeSuspend(Example.kt:52)
Compilable test class that uses yield() calls to force 4 continuation resume calls:
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
import org.junit.Test
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mockito.*
class Example {
companion object {
const val YIELDS = 4
fun log(msg: String) {
with(Thread.currentThread()) { println("[$id: $name]: $msg") }
}
}
private val foobarMock = mock(Foobar::class.java)
class Foobar {
suspend fun foobar(spins: Int) {
repeat(spins) {
yield()
}
}
}
@Test
fun `matcher foobar(anyInt()) matches original call and all continuation resume calls`() {
runBlocking {
`when`(foobarMock.foobar(anyInt())).thenCallRealMethod()
callFoobar()
// Total calls should be first call plus the number of yields.
verify(foobarMock, times(1 + YIELDS)).foobar(anyInt())
}
}
@Test
fun `matcher foobar(eq(Int)) matches original call but NO continuation resume calls`() {
runBlocking {
`when`(foobarMock.foobar(eq(YIELDS))).thenCallRealMethod()
callFoobar()
// Total calls should be first call plus the number of yields.
verify(foobarMock, times(1 + YIELDS)).foobar(eq(YIELDS))
}
}
suspend fun callFoobar() = coroutineScope {
val job = launch {
foobarMock.foobar(YIELDS)
}
repeat(YIELDS) { yield() }
job.join()
}
}
The text was updated successfully, but these errors were encountered:
Version Mockito 3.2.4
JDK 8
Ubuntu 18.04
Test run in Android Studio IDE 3.5.3
Using the eq() argument matcher when calling any Kotlin suspend function will always match the first (original) call, but will fail to match any continuation resume calls made by the Kotlin coroutine framework.
However, if you change the eq() to any() or anyInt() (if your function argument is an Int value), then the argument matcher will work for the original call and all subsequent continuation resume calls.
I realize that there is an extra hidden parameter but it seems to me that if eq() succeeds in the original test call, it should also succeed for the continuation resume calls.
The following 2 test in the test class provided below will produce TooFewActualInvocations for the 2nd test:
Test output:
Compilable test class that uses yield() calls to force 4 continuation resume calls:
The text was updated successfully, but these errors were encountered: