question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Wrong stub is being created if an extension function call on a mock is passed as an argument directly when stubbing

See original GitHub issue

Hi! 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:open
  • Created 2 years ago
  • Reactions:2
  • Comments:13

github_iconTop GitHub Comments

1reaction
ghostcommented, Jan 17, 2022

@Raibaz It seems that inside the lambda which is passed to every() properties of the mocks are returning incorrect values.

When running

val processor = mockk<Processor> {
    every {
        println("Creation data is ${version.creationDate}.")
        processVersion(version)
    } returns Unit
}

I see Screenshot 2022-01-17 at 10 36 56 and

Creation data is .

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. 😉

0reactions
stale[bot]commented, Jul 10, 2022

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 an important label.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mockito - NullpointerException when stubbing Method
I was getting errors that made no sense but using Mockito.anyInt() rather than Mockito.any() solved it. Example Error: org.mockito.exceptions.
Read more >
Mockito (Mockito 4.9.0 API) - Javadoc.io
The Mockito library enables mock creation, verification and stubbing. ... It allows access to documentation straight from the IDE even if you work...
Read more >
Verify that functions were called | Mocking | MockK Guidebook
In MockK, this is accomplished using the verify function. Using verify to verify that a function was called looks a lot like using...
Read more >
Returning stubbed HTTP responses to specific requests
Stubbing. A core feature of WireMock API mocking is the ability to return canned HTTP ... To create the stub described above via...
Read more >
8. Test Doubles — PHPUnit 9.5 Manual - Read the Docs
Example 8.2 shows how to stub method calls and set up return values. ... Example 8.5 Stubbing a method call to return one...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found