mockito / mockito-kotlin

Using Mockito with Kotlin
MIT License
3.11k stars 201 forks source link

Invocation count is wrong when capturing arguments against sealed class types #349

Open gosr opened 5 years ago

gosr commented 5 years ago

Assume you have a sealed class hierarchy as follows:

sealed class MyType {
  data class Open(val something: String) : MyType()
  data class Finish(val reason: String) : MyType()
}

Let's say the production code that I'm verifying against has a method with the following structure:

class MyClass {
  fun doStuff(myType: MyType) {
    // ...
  }
}

So, somewhere in the production code we do this: myClass.doStuff(MyType.Open("something")). Later, in another place, we do this: myClass.doStuff(MyType.Finish("reason")).

In my test, this is the setup I am trying to use for verifying that myClass invoked doStuff() exactly once with the parameter MyType.Finish:

import com.nhaarman.mockitokotlin2.argumentCaptor
import org.mockito.Mockito.*

@Test
fun someTest() {
  argumentCaptor<MyType.Finish>().apply {
    verify(myClass, times(1)).send(capture())
  }
}

The test fails with the following output:

org.mockito.exceptions.verification.TooManyActualInvocations: myClass.doStuff(); Wanted 1 time: -> at "location in test method" But was 2 times: -> at "location where I call myClass.doStuff(MyType.Open("something"))" -> at "location where I call myClass.doStuff(MyType.Finish("reason"))"

So, the argumentCaptor specified with the type MyType.Finish captures all invocations where the superclass MyType is used.

nhaarman commented 5 years ago

This seems to be related: https://stackoverflow.com/questions/5403706/using-mockitos-argumentcaptor-class-to-match-a-child-class