Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: capture Slots in multiple verifications capture only last value #352

Closed
tmarsteel opened this issue Sep 12, 2019 · 6 comments · Fixed by #533
Closed

Bug: capture Slots in multiple verifications capture only last value #352

tmarsteel opened this issue Sep 12, 2019 · 6 comments · Fixed by #533

Comments

@tmarsteel
Copy link

tmarsteel commented Sep 12, 2019

Expected Behavior & Current Behaviour

Capturing slots work like you'd expect them to, coming from mockito. See this test-case:

open class MockedSubject {
    open fun doSomething(id: String?, data: Any?): String {
        throw IllegalStateException("Not mocked :(")
    }
}

val mock = mockk<MockedSubject>()

every { mock.doSomething("1", "data1") } returns "result1"
every { mock.doSomething("2", "data2") } returns "result2"

mock.doSomething("1", "data1")
mock.doSomething("2", "data2")

val dataSlotId1 = slot<String>()
val dataSlotId2 = slot<String>()

verify (exactly = 1) { mock.doSomething("1", capture(dataSlotId1)) }
verify (exactly = 1) { mock.doSomething("2", capture(dataSlotId2)) }

dataSlotId1.captured shouldBe "data1"
dataSlotId2.captured shouldBe "data2"

This fails because dataSlotId1.captured is "data2"

Steps to Reproduce

I've put all code necessary to reproduce here: https://github.com/tmarsteel/mockk-verify-capture-test

Just run mvn clean test or run the test in your IDE.

Context

See the pom.xml in the repository.

  • MockK version: 1.9.3
  • OS: Ubuntu 18.04
  • Kotlin version: 1.3.41
  • JDK version: fails on OpenJDK 1.8.0_222 and 11.0.2 and HotSpot 10.0.2
  • JUnit version: fails with 4.12 and Jupiter 5.5.1
  • Type of test: unit test

Failure Logs

Screenshot from 2019-09-12 11-20-28

Stack trace

from the screenshot:

org.opentest4j.AssertionFailedError: expected: "data1" but was: "data2"
Expected :"data1"
Actual   :"data2"
<Click to see difference>


	at com.acme.ExampleTest.test(MockkDebugTest.kt:30)
	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:532)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
@oleksiyp oleksiyp changed the title Capture Slots in multiple verifications capture only last value Bug: capture Slots in multiple verifications capture only last value Nov 2, 2019
@oleksiyp oleksiyp added this to the 1.9.4 milestone Nov 2, 2019
@oleksiyp oleksiyp added this to To do in Critical to fix Nov 2, 2019
@tunovic
Copy link

tunovic commented Feb 28, 2020

@tmarsteel Maybe not ideal, but have you tried verifyOrder?

verifyOrder {
    mock.doSomething("1", capture(dataSlotId1)) 
    mock.doSomething("2", capture(dataSlotId2))
}

@only-fabione
Copy link

only-fabione commented Jul 1, 2020

Did you try using a list instead of a slot and then capture it?
I did it in this way and it works

val slotIds = mutableListOf<String>()
every { mock.doSomething(capture(slotIds)) } just Runs
val firstSlot = slotIds[0]
val secondSlot = slotIds[1]

@tmarsteel
Copy link
Author

@tunovic @only-fabione both work. I don't know how i solved it back then, probably with the list.

@Raibaz
Copy link
Collaborator

Raibaz commented Nov 24, 2020

Sent out #533 to fix this.

The fix is actually suggesting what @only-fabione said earlier, to use a mutableList when capturing the same function arguments more than once.

It should be clearer now why MockK is not behaving as expected when using slots in this case.

Critical to fix automation moved this from To do to Done Nov 29, 2020
@nidhindev
Copy link

Did you try using a list instead of a slot and then capture it?
I did it in this way and it works

val slotIds = mutableListOf<String>()
every { mock.doSomething(capture(slotIds)) } just Runs
val firstSlot = slotIds[0]
val secondSlot = slotIds[1]

Thanks This works

@orpheus
Copy link

orpheus commented Mar 22, 2022

Did you try using a list instead of a slot and then capture it? I did it in this way and it works

val slotIds = mutableListOf<String>()
every { mock.doSomething(capture(slotIds)) } just Runs
val firstSlot = slotIds[0]
val secondSlot = slotIds[1]

Neat trick, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

7 participants