mockk / mockk

mocking library for Kotlin
https://mockk.io
Apache License 2.0
5.44k stars 346 forks source link

Failed matching mocking signature for open suspended functions #1057

Open vlylozian opened 1 year ago

vlylozian commented 1 year ago

Expected Behavior

I expect my test to be green when testing open suspended functions in an abstract class

Current Behavior

The unit tests are failing to match the mocking signature

Failure Information (for bugs)

From the code snippets below, we have a SingleTestA where we inject an instance of SingleTestB which extends an abstract class AbstractTest, AbstractTest includes an open suspended function suspendedOpenFunction, when verifying the testB() function we get the exception below.

The tests succeed when removing either the open keyword or the suspend in the method suspendedOpenFunction.

Stack trace

Failed matching mocking signature for

left matchers: [any()]
io.mockk.MockKException: Failed matching mocking signature for

left matchers: [any()]
    at app//io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:97)
    at app//io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
    at app//io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
    at app//io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
    at app//io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
    at app//io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30)
    at app//io.mockk.MockKDsl.internalCoVerify(API.kt:145)
    at app//io.mockk.MockKKt.coVerify(MockK.kt:244)
    at app//io.mockk.MockKKt.coVerify$default(MockK.kt:235)
    at app//com.sixt.one.base.architecture.issue.SingleTestImplTest$test test$1.invokeSuspend(SingleTestImplTest.kt:31)
internal class SingleTestImplTest {

    @MockK
    private lateinit var singleTestB : SingleTestB

    @Before
    fun before() {
        MockKAnnotations.init(this, relaxUnitFun = true)
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun `test test`() = runTest {
        val sut = SingleTestA(singleTestB)

        sut.testB()

        coVerify { singleTestB.testIt(any()) }
    }

}
class SingleTestA(private val singleTestB: SingleTestB) {

    fun testB() {
        singleTestB.testIt(SingleTestB.Intent("test"))
    }

}
class SingleTestB : AbstractTest<SingleTestB.Intent>() {

    data class Intent(val str: String)

}
abstract class AbstractTest<T> {

    fun testIt(intent: T) : Flow<String> {
        return MutableSharedFlow<String>().onStart {
            suspendedOpenFunction(intent)
        }
    }

    open suspend fun suspendedOpenFunction(intent: T): Boolean {
        return false
    }
}
deyvi-ifit commented 1 year ago

Also seeing the same issue. Removing open from the function allows the tests to pass but I feel like there should be a way to test this without having to change production code