mockk / mockk

mocking library for Kotlin
https://mockk.io
Apache License 2.0
5.34k stars 335 forks source link

Mockk failing when targeting Java 21 #1249

Open slw546 opened 1 month ago

slw546 commented 1 month ago

Prerequisites

Please answer the following questions for yourself before submitting an issue.

Expected Behavior

Demo code from the mockk readme should work when targeting jvm 21 in kotlin-maven-plugin

Current Behavior

Using the demo code blocks, i.e.

    class Adder {
        fun addOne(num: Int) = num + 1
    }

    @Test
    fun test() {
        val adder = io.mockk.mockk<Adder>()

        io.mockk.every { adder.addOne(1) } returns -1
        io.mockk.every { adder.addOne(3) } answers { callOriginal() }

        assertEquals(-1, adder.addOne(2))
        assertEquals(4, adder.addOne(3)) // original function is called
    }

Mockk methods do not appear to return a mock when called only under JVM 21. I.e. if I target up to 20: io.mockk.mockk<Adder>(relaxed = false).addOne() will throw an MockK exception as expected: no answer found for com.Testy$Adder@1931d99.addOne(1) among the configured answers: ()

Calling the same code with a JVM target of 21 throws no exceptions. In effect I seem to have a concrete instance of the class, or at least a relaxed mock, as I can call addOne and get a correct response - i.e it's calling the underlying method. However, it cannot be used as a proper mock and will instead blow up in the every block:

io.mockk.MockKException: Failed matching mocking signature for

left matchers: [any()]

    at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:97)
    at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
    at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
    at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
    at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:62)
    at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    at io.mockk.MockKDsl.internalEvery(API.kt:94)
    at io.mockk.MockKKt.every(MockK.kt:143)
    at com.vortexa.homework.metrics.Testy.test(Testy.kt:20)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:139)
    ...

Indeed if you add a verify block it'll blow up looking suspiciously like it can't find a mock at all inside the verify: io.mockk.MockKException: Missing calls inside verify { ... } block, equally on Objects, you'll get the Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock - all implying the return is no longer a proper mock under 21.

Failure Information (for bugs)

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Use one of the mockk examples in the readme

  2. Set your kotlin compiler to e.g. in the pom <jvmTarget>21</jvmTarget>, or equivalent for gradle:

            <plugin>
                <groupId>org.jetbrains.kotlin</groupId>
                <artifactId>kotlin-maven-plugin</artifactId>
                <version>1.9.23</version>
                <configuration>
                    <jvmTarget>21</jvmTarget>
                    <args>
                        <arg>-Xjsr305=strict</arg>
                    </args>
                    <compilerPlugins>
                        <plugin>spring</plugin>
                    </compilerPlugins>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jetbrains.kotlin</groupId>
                        <artifactId>kotlin-maven-allopen</artifactId>
                        <version>${kotlin.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                    <execution>
                        <id>test-compile</id>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                        <phase>test-compile</phase>
                    </execution>
                </executions>
            </plugin>
  3. The code will blow up

  4. Set the target to 20 and the same code will work

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

Stack trace

io.mockk.MockKException: Failed matching mocking signature for

left matchers: [any()]

    at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:97)
    at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
    at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
    at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
    at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:62)
    at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    at io.mockk.MockKDsl.internalEvery(API.kt:94)
    at io.mockk.MockKKt.every(MockK.kt:143)
    at com.vortexa.homework.metrics.Testy.test(Testy.kt:20)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

Minimal reproducible code (the gist of this issue)

package com.vortexa.homework.metrics

import org.junit.Assert.assertEquals
import org.junit.Test

class Testy {

    class Adder {
        fun addOne(num: Int) = num + 1
    }

    @Test
    fun test() {
        val adder = io.mockk.mockk<Adder>

        io.mockk.every { adder.addOne(1) } returns -1
        io.mockk.every { adder.addOne(3) } answers { callOriginal() }

        assertEquals(-1, adder.addOne(2))
        assertEquals(4, adder.addOne(3)) // original function is called
    }
BenjaminBeeker commented 2 weeks ago

Have the same issue with