mockito / mockito-kotlin

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

IncompatibleClassChangeError when using argThat #307

Open Octogonapus opened 5 years ago

Octogonapus commented 5 years ago

I get an IncompatibleClassChangeError with any use of the argThat matcher. Full stacktrace: https://pastebin.com/4hr67L0r. I am using version 2.0.0.

Here is a simple example I replicated the problem with:

interface Foo {
    fun doIt(arg: Int): Int
}

class TestClass {
    @Test
    fun testIt() {
        mock<Foo> {
            on { doIt(argThat { true }) } doReturn 0
        }
    }
}
bohsen commented 5 years ago

@Octogonapus I get a NullPointerException with the provided example. This is caused by Mockito.argThat which Mockito-kotlin uses under the hood. If you check the javadoc on Mockito.argThat they recommend you to use booleanThat instead:

class TestClass {
    @Test
    fun testIt() {
        val mock = mock<Foo> {
            on { doIt(booleanThat { true } doReturn 0
        }
    }
}

This should pass.

Octogonapus commented 5 years ago

@bohsen Foo::doIt() does not take a boolean, so I can't use booleanThat. In my real code, it takes a complex argument so I think I need to use argThat.

bohsen commented 5 years ago

@Octogonapus In that case just call equals inside argThat (if equals is an option for the given argument). Example using a data class as argument:

interface Foo {
    fun doIt(arg: DataClass): Int
}

data class DataClass(i: Int, b: Boolean, s: String)

class TestClass {
    @Test
    fun testIt() {
        val data = DataClass(42, true, "foobar")
        val mock = mock<Foo> {
            on { doIt(argThat { equals(data) } doReturn 0
        }
        myObjectThatCallsMyMock.baz(data)
        ... verify ...
    }
}

Otherwise use an ArgumentMatcher.

Octogonapus commented 5 years ago

Hm, that is what I was trying to do. I am starting to think my example was a bit too simple. Here is the actual code:

        val mockWristIdentifier = mock<WristIdentifier> {
            on { isSphericalWrist(or(wrist, wrist2)) } doReturn Option.empty()
            on {
                isSphericalWrist(argThat {
                    !(equals(wrist) || equals(wrist2))
                })
            } doReturn Option.just(ClassifierError(""))
        }

My intent is to return Option.empty() for either wrist or wrist2 and return Option.just(ClassifierError("")) otherwise. Does this look like the right usage to you?

timbaer commented 5 years ago

Hi folks,

I get the same exception when using "check". My example:

doReturn(stuff).whenever(mock).fetchData(check {
   assertThat(it.dayOfYear).isEqualTo(otherDate.dayOfYear)
   assertThat(it.year).isEqualTo(otherDate.year)
})

Exception is:

java.lang.IncompatibleClassChangeError: Implementing class at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) at java.net.URLClassLoader.access$100(URLClassLoader.java:73) at java.net.URLClassLoader$1.run(URLClassLoader.java:368) at java.net.URLClassLoader$1.run(URLClassLoader.java:362) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:361) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

When debugging, I can see that the code is trying to load a class by name path.to.clazz.MyTest$givenApiReturns$$inlined$check$1

which (obviously I would say) fails, because this clazz cannot exists.

On:

kTT commented 5 years ago

@Octogonapus @timbaer I had same issue with mockito-kotlin 2.1.0 and I fixed it by adding explicit dependency to mockito-core 2.23.0

kevcodez commented 5 years ago

Also running into NullPointerExceptions with mockito-kotlin 2.1.0

bes89 commented 4 years ago

Adding explicit dependency to testImplementation("org.mockito:mockito-core:2.23.0") solve the issue for me, thanks @kevcodez