mockk: Bug: for classes generated by Retrofit spies fail in coVerification clause on suspend functions
Expected Behavior
A verification on a suspend function of a spy object is possible.
Current Behavior
The verification fails always.
Failure Information (for bugs)
I was trying to verify a call on a suspend function belonging to a spy object, the implementation of the function is generated code by retrofit. Since version 2.6.0 retrofit allows the use of the suspend modifier. The assertion error returned is:
java.lang.AssertionError: Verification failed: call 1 of 1: $Proxy7(#1).getTest(eq(continuation {}))). Only one matching call to $Proxy7(#1)/getTest(Continuation) happened, but arguments are not matching: [0]: argument: continuation {}, matcher: eq(continuation {}), result: -
Steps to Reproduce
- Create a spy on a retrofit service exposing an endpoint as a suspend function
- Trigger a call to said endpoint in a test
- Coverify this call
Context
- MockK version: 1.9.3
- OS: Mac OS 10.14.5
- Kotlin version: 1.3.41
- JDK version: OpenJDK 1.8.0_152-release (embedded in AS 3.4.2)
- JUnit version: 4.12
- Type of test: unit test
- Retrofit version: 2.6.1
Stacktrace
Stack trace:
io.mockk.impl.InternalPlatform.captureStackTrace (InternalPlatform.kt:121)
io.mockk.impl.stub.MockKStub.handleInvocation (MockKStub.kt:247)
io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation (JvmMockFactoryHelper.kt:25)
io.mockk.proxy.jvm.advice.Interceptor.call (Interceptor.kt:20)
com.sun.proxy.$Proxy7.getTest (-:-1)
com.example.myapplication.TestSubject$test$1.invokeSuspend (TestSubject.kt:8)
kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33)
kotlinx.coroutines.DispatchedTask.run (Dispatched.kt:238)
kotlinx.coroutines.EventLoopImplBase.processNextEvent (EventLoop.kt:116)
kotlinx.coroutines.BlockingCoroutine.joinBlocking (Builders.kt:80)
kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking (Builders.kt:54)
kotlinx.coroutines.BuildersKt.runBlocking (-:1)
kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default (Builders.kt:36)
kotlinx.coroutines.BuildersKt.runBlocking$default (-:1)
com.example.myapplication.TestSubject.test (TestSubject.kt:7)
com.example.myapplication.TestSubjectTest.test (TestSubjectTest.kt:34)
sun.reflect.NativeMethodAccessorImpl.invoke0 (NativeMethodAccessorImpl.java:-2)N
sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke (Method.java:498)
org.junit.runners.model.FrameworkMethod$1.runReflectiveCall (FrameworkMethod.java:50)
org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:12)
org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:47)
org.junit.internal.runners.statements.InvokeMethod.evaluate (InvokeMethod.java:17)
org.junit.runners.ParentRunner.runLeaf (ParentRunner.java:325)
org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:78)
org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:57)
org.junit.runners.ParentRunner$3.run (ParentRunner.java:290)
org.junit.runners.ParentRunner$1.schedule (ParentRunner.java:71)
org.junit.runners.ParentRunner.runChildren (ParentRunner.java:288)
org.junit.runners.ParentRunner.access$000 (ParentRunner.java:58)
org.junit.runners.ParentRunner$2.evaluate (ParentRunner.java:268)
org.junit.runners.ParentRunner.run (ParentRunner.java:363)
org.junit.runner.JUnitCore.run (JUnitCore.java:137)
com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs (JUnit4IdeaTestRunner.java:68)
com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs (IdeaTestRunner.java:47)
com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart (JUnitStarter.java:242)
com.intellij.rt.execution.junit.JUnitStarter.main (JUnitStarter.java:70) (timeout = 5000 ms)
at io.mockk.impl.recording.states.VerifyingState.failIfNotPassed(VerifyingState.kt:66)
at io.mockk.impl.recording.states.VerifyingState.recordingDone(VerifyingState.kt:42)
at io.mockk.impl.recording.CommonCallRecorder.done(CommonCallRecorder.kt:47)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:60)
at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalCoVerify(API.kt:143)
at io.mockk.MockKKt.coVerify(MockK.kt:162)
at io.mockk.MockKKt.coVerify$default(MockK.kt:159)
at com.example.myapplication.TestSubjectTest.test(TestSubjectTest.kt:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Minimal reproducible code (the gist of this issue)
package com.example.myapplication
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.spyk
import okhttp3.OkHttpClient
import org.junit.Test
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class TestSubjectTest {
val okhttp = OkHttpClient.Builder().build()
val testApi = spyk(Retrofit.Builder() // THIS DOES NOT WORK
.baseUrl("https://jsonplaceholder.typicode.com")
.addConverterFactory(GsonConverterFactory.create())
.client(okhttp).build().create(TestApi::class.java))
// val testApi: TestApi = mockk { // THIS WORKS
// coEvery { getTest() } returns Dto(1, 1, "", false)
// }
val testSubject = TestSubject(testApi)
@Test
fun test() {
testSubject.test()
coVerify { testApi.getTest() }
}
}
package com.example.myapplication
import retrofit2.http.GET
interface TestApi {
@GET("/todos/1")
suspend fun getTest(): Dto
}
data class Dto(val userId: Int, val id: Int, val title: String, val completed: Boolean)
package com.example.myapplication
import kotlinx.coroutines.runBlocking
class TestSubject(private val testApi: TestApi) {
fun test() {
runBlocking {
testApi.getTest()
}
}
}
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 5
- Comments: 25 (1 by maintainers)
Hi folks, we build a solution based on @palatin example.
Usage:
We also have to create functions for the amount of parameters that we required.
@DevSrSouza Iām not able to find
KSuspendFunction1
, what Kotlin version are you using?Mine is
1.4.31
The simplest MWE tests that fail with:
Stacktraces: