Wrong stub is being created if an extension function call on a mock is passed as an argument directly when stubbing
See original GitHub issueHi! I’m experiencing a strange behaviour with MockK. Not sure if it’s a bug or I’m just not getting something. Couldn’t find anything about the problem, so posting it here.
The problem is that if an extension function call on a mock is passed as an argument directly when stubbing another mock, a wrong stub is being created. But if the result of such extension function call is saved in a variable and this variable is then passed as an argument, everything works fine.
This is reproducible when using both Kotlin 1.5.31
and 1.6.0
with MockK 1.12.1
Please note that in order to make the example shorter I’m not putting the code inside a test.
Minimal reproducible code (the gist of this issue)
import io.mockk.every
import io.mockk.mockk
import java.time.Instant
class Version {
lateinit var creationDate: Instant
}
class Document {
lateinit var versions: List<Version>
}
fun Document.latestVersion() = versions.maxByOrNull(Version::creationDate)
class Processor {
fun processVersion(version: Version?) = println("Processing $version.")
}
fun main() {
val version = mockk<Version> {
every { creationDate } returns Instant.EPOCH
}
val document = mockk<Document> {
every { versions } returns listOf(version)
}
val processor = mockk<Processor> {
every { processVersion(document.latestVersion()) } returns Unit
}
processor.processVersion(document.latestVersion())
}
Stack trace
Exception in thread "main" io.mockk.MockKException: no answer found for: Iterator(child^2 of #3#4#6).hasNext()
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:266)
at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:23)
at io.mockk.proxy.jvm.advice.Interceptor.call(Interceptor.kt:21)
at io.mockk.proxy.jvm.advice.BaseAdvice.handle(BaseAdvice.kt:42)
at io.mockk.proxy.jvm.advice.jvm.JvmMockKProxyInterceptor.interceptNoSuper(JvmMockKProxyInterceptor.java:45)
at io.mockk.renamed.java.util.Iterator$Subclass1.hasNext(Unknown Source)
at TestKt.latestVersion(test.kt:35)
at TestKt.main(test.kt:31)
at TestKt.main(test.kt)
If instead of passing document.latestVersion()
directly when stubbing a separate variable is used, code runs without any problems:
val versionToProcess = document.latestVersion()
val processor = mockk<Processor> {
every { processVersion(versionToProcess) } returns Unit
}
processor.processVersion(document.latestVersion())
Issue Analytics
- State:
- Created 2 years ago
- Reactions:2
- Comments:13
Top GitHub Comments
@Raibaz It seems that inside the lambda which is passed to
every()
properties of the mocks are returning incorrect values.When running
I see and
is printed to the output. 😅
Sure, I totally agree that two mocks should not be used in a single
every
block. 🙂Yes, it might be the correct behaviour, but it doesn’t sound to me that implementing this would be easy. I guess it will be even harder to make two mocks work in a single
every
block. 😄 Maybe it would be enough for now to update the documentation to warn users about potential problems. 😉This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. If you are sure that this issue is important and should not be marked as
stale
just ask to put animportant
label.