mockk / mockk

mocking library for Kotlin

Home Page:https://mockk.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No answer found for: `...continuation {})`

igorwojda opened this issue · comments

Prerequisites

Please answer the following questions for yourself before submitting an issue.

  • I am running the latest version
  • I checked the documentation and found no answer
  • I checked to make sure that this issue has not already been filed

Expected Behavior

Mockk handles the implicit continuation parameter

Current Behavior

Method mock is not working

Failure Information (for bugs)

Exception in thread "Test worker @coroutine#4" io.mockk.MockKException: no answer found for:
GetAlbumUseCase(#1).execute(Thriller, Michael Jackson, 123, continuation {})

Steps to Reproduce

I could not extract this issue into a self-contained code sample, however, I have created a dedicated branch in my project where you can quickly reproduce this issue:

https://github.com/igorwojda/android-showcase/tree/mockk-continuation-no-answear-bug

  1. Open AlbumDetailViewModelTest class
  2. Remove @Disabled("mockk can't correctly mock this function") annotation
  3. Run the onEnter album is not found test

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • MockK version: "1.13.2"
  • OS: MacOs BigSur / Ventura
  • Kotlin version: 1.7.20
  • JDK version: openjdk 19 2022-09-20
  • JUnit version: 5.9.1
  • Type of test: unit test OR android instrumented test: Unit test

Stack trace

Exception in thread "Test worker @coroutine#4" io.mockk.MockKException: no answer found for: GetAlbumUseCase(#1).execute(Thriller, Michael Jackson, 123, continuation {})
	at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)
	at io.mockk.impl.stub.MockKStub.answer(MockKStub.kt:42)
	at io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:16)
	at io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
	at io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:271)
	at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:24)
	at io.mockk.proxy.jvm.advice.Interceptor.call(Interceptor.kt:21)
	at com.igorwojda.showcase.feature.album.domain.usecase.GetAlbumUseCase.execute(GetAlbumUseCase.kt:15)
	at com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModel$getAlbum$1.invokeSuspend(AlbumDetailViewModel.kt:31)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.test.TestDispatcher.processEvent$kotlinx_coroutines_test(TestDispatcher.kt:28)
	at kotlinx.coroutines.test.TestCoroutineScheduler.tryRunNextTaskUnless$kotlinx_coroutines_test(TestCoroutineScheduler.kt:100)
	at kotlinx.coroutines.test.TestCoroutineScheduler.advanceUntilIdleOr$kotlinx_coroutines_test(TestCoroutineScheduler.kt:120)
	at kotlinx.coroutines.test.TestCoroutineScheduler.advanceUntilIdle(TestCoroutineScheduler.kt:113)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTestCoroutine(TestBuilders.kt:237)
	at kotlinx.coroutines.test.TestBuildersKt.runTestCoroutine(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invokeSuspend(TestBuilders.kt:167)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invoke(TestBuilders.kt)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt$runTest$1$1.invoke(TestBuilders.kt)
	at kotlinx.coroutines.test.TestBuildersJvmKt$createTestResult$1.invokeSuspend(TestBuildersJvm.kt:13)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersJvmKt.createTestResult(TestBuildersJvm.kt:12)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest(TestBuilders.kt:166)
	at kotlinx.coroutines.test.TestBuildersKt.runTest(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest(TestBuilders.kt:154)
	at kotlinx.coroutines.test.TestBuildersKt.runTest(Unknown Source)
	at kotlinx.coroutines.test.TestBuildersKt__TestBuildersKt.runTest$default(TestBuilders.kt:147)
	at kotlinx.coroutines.test.TestBuildersKt.runTest$default(Unknown Source)
	at com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModelTest.onEnter album is not found(AlbumDetailViewModelTest.kt:27)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [CoroutineId(4), "coroutine#4":StandaloneCoroutine{Cancelling}@340d6d89, Dispatchers.Main]

Expected: <com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModel$UiState$Error@37854b34> but was: <com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModel$UiState$Loading@2ddb3ae8>
Expected :com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModel$UiState$Error@37854b34
Actual   :com.igorwojda.showcase.feature.album.presentation.screen.albumdetail.AlbumDetailViewModel$UiState$Loading@2ddb3ae8

I got the same error with the example
kotlin 1.5.30
mockk 1.11.0
kotlinx-coroutines-core-jvm: 1.5.2

import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.awaitBodilessEntity

internal class ExampleTest {

    @Test
    fun test(): Unit = runBlocking {
        val dep = mockk<Dep>()
        val example = Example(dep)
        val entity = mockk<Entity>()
        every { entity.param1 } returns 5
        every { entity.param2 } returns 56
        coEvery { dep.func1(entity.param1, entity.param2) } returns "mockk answer dep func1"

        val res = example.exampleTest(entity)

        coVerify(exactly = 1) { dep.func1(entity.param1, entity.param2) }
        assert(res == "example test complete")
    }

    class Example(
        private val dep: Dep,
    ) {
        suspend fun exampleTest(entity: Entity): String {
            dep.func1(entity.param1, entity.param2)
            return "example test complete"
        }
    }

    class Dep(
        private val webClient: WebClient,
    ) {
        suspend fun func1(param1: Int, param2: Long): String {
            println("this is params: $param1 $param2")
            webClient.get().uri("/localhost").retrieve().awaitBodilessEntity()
            return "dep func1 complete"
        }
    }

    data class Entity(
        val param1: Int,
        val param2: Long,
    )
}

log

08:49:05.903 [Test worker @coroutine#1] DEBUG io.mockk.impl.instantiation.AbstractMockFactory - Creating mockk for Dep name=#1
08:49:06.282 [Test worker @coroutine#1] DEBUG io.mockk.impl.instantiation.AbstractMockFactory - Creating mockk for Entity name=#2
08:49:07.429 [Test worker @coroutine#1] DEBUG io.mockk.impl.instantiation.AbstractMockFactory - Creating mockk for Any name=child of #1#3
08:49:07.435 [Test worker @coroutine#1] DEBUG io.mockk.impl.recording.states.AnsweringState - Answering 5 on Entity(#2).getParam1()
08:49:07.436 [Test worker @coroutine#1] DEBUG io.mockk.impl.recording.states.AnsweringState - Answering 56 on Entity(#2).getParam2()
08:49:07.439 [Test worker @coroutine#1] DEBUG io.mockk.impl.recording.states.AnsweringState - Throwing io.mockk.MockKException: no answer found for: Dep(#1).func1(5, 56, continuation {}) on Dep(#1).func1(5, 56, continuation {})

no answer found for: Dep(#1).func1(5, 56, continuation {})
io.mockk.MockKException: no answer found for: Dep(#1).func1(5, 56, continuation {})
	at app//io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:90)
	at app//io.mockk.impl.stub.MockKStub.answer(MockKStub.kt:42)
	at app//io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:16)
	at app//io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
	at app//io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:263)
	at 

In my case solution was

val entity = Entity(5, 56)
coEvery { dep.func1(entity.param1, entity.param2) } returns "mockk answer dep func1"

It seems usage of mock entity and then pass their properties in method arguments produces such error.

@igorwojda I am facing the same issue and have not solved yet. have you solved this issue?

Not solved

Not solved

okay

Same for me, mockk 1.13.5.

@igorwojda The issue is with the Dispatcher rule made for suspend functions. working fine for me.

use the below code and define this rule into your viewmodel test class.

@OptIn(ExperimentalCoroutinesApi::class)
class MainDispatcherRule(
private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()
) : TestWatcher() {

override fun starting(description: Description) {
    super.starting(description)
    Dispatchers.setMain(testDispatcher)
}

override fun finished(description: Description) {
    super.finished(description)
    Dispatchers.resetMain()
}

}

My experience with this has been weird, but I want to share in case is useful for somebody:
Basically i was having the same error than reported in this issue. I was actually being shown two errors, this one and one after that I thought was caused by the continuation() thing (an assertion of intent failing, thinking it was returning default value).
However when I fixed the assertion of the second error, the test ended up working OK and the continuation issue ended up posing no problem.