mockk icon indicating copy to clipboard operation
mockk copied to clipboard

Cannot use `mockkObject` in a interface's lambda implementation

Open marcusdacoregio opened this issue 3 years ago • 3 comments

Just be aware about usual MockK support pattern. Tickets are checked from time to time, replied, discussed, labeled, e.t.c. But real fixes are applied in a month-two month period in a bunch. If you think this is unacceptable, go on, join the project, change the world.

Please remove sections wisely

Below information is actually needed to make all the process of fixing faster. Choose main points. Don't blindly follow this as a set of rules. Don't waste much time. Usually, the main thing is to have a good reproducible minimal code.

Prerequisites

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

  • [x] I am running the latest version
  • [x] I checked the documentation and found no answer
  • [x] I checked to make sure that this issue has not already been filed

Expected Behavior

The interface implementation inside an inner class should be mocked when using mockkObject

Current Behavior

When switching from Kotlin language version 1.4 to 1.5 a warning start to happen when running the test WARNING: Non instrumentable classes(skipped): class CustomInterfaceTests$Config$$Lambda$311/0x00000008001da440. With this warning, the object cannot be mocked, therefore failing inside the every { ... }

Failure Information (for bugs)

Jan 13, 2022 10:49:00 AM io.mockk.impl.log.JULLogger warn
WARNING: Non instrumentable classes(skipped): class CustomInterfaceTests$Config$$Lambda$311/0x00000008001da440

Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Create a Java interface, i.e CustomInterface with a single method void doStuff()
  2. Create a test, mock the interface inside the test
class CustomInterfaceTests {

    val CUSTOM_INTERFACE: CustomInterface = CustomInterface { }

    @Test
    fun `test`() {
        mockkObject(CUSTOM_INTERFACE)
        every { CUSTOM_INTERFACE.doStuff() } returns Unit
    }

}
  1. Run the test and see that it fails with the stacktrace provided
  2. Instead of val CUSTOM_INTERFACE: CustomInterface = CustomInterface { }, use val CUSTOM_INTERFACE: CustomInterface = CustomInterfaceImpl(), the test passes.
  3. If lowering the language version < 1.5, the test passes

Context

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

  • MockK version: 1.12.2
  • OS: macOS Big Sur 11.6.1
  • Kotlin version: 1.6.10
  • JDK version: 11
  • JUnit version: 5
  • Type of test: unit test

Failure Logs

Please include any relevant log snippets or files here.

Stack trace

Jan 13, 2022 10:59:22 AM io.mockk.impl.log.JULLogger warn
WARNING: Non instrumentable classes(skipped): class CustomInterfaceTests$$Lambda$288/0x00000008001d4440

Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
	at io.mockk.impl.recording.states.StubbingState.checkMissingCalls(StubbingState.kt:14)
	at io.mockk.impl.recording.states.StubbingState.recordingDone(StubbingState.kt:8)
	at io.mockk.impl.recording.CommonCallRecorder.done(CommonCallRecorder.kt:47)
	at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:64)
	at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
	at io.mockk.MockKDsl.internalEvery(API.kt:93)
	at io.mockk.MockKKt.every(MockK.kt:98)

Minimal reproducible code (the gist of this issue)

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.6.10"
    application
}

group = "me.mhertdacoreg"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(kotlin("test"))
    implementation("io.mockk:mockk:1.12.2")
}

tasks.test {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        languageVersion = "1.5"
        apiVersion = "1.5"
        jvmTarget = "11"
    }
}

application {
    mainClass.set("MainKt")
}
public interface CustomInterface {

	void doStuff();

}
import io.mockk.every
import io.mockk.mockkObject
import org.junit.jupiter.api.Test

class CustomInterfaceTests {

    val CUSTOM_INTERFACE: CustomInterface = CustomInterface { }
   //     val CUSTOM_INTERFACE: CustomInterface = CustomInterfaceImpl()

    @Test
    fun `test`() {
        mockkObject(CUSTOM_INTERFACE)
        every { CUSTOM_INTERFACE.doStuff() } returns Unit
    }

}

Am I missing some change between 1.4 and 1.5?

marcusdacoregio avatar Jan 13 '22 13:01 marcusdacoregio

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.

stale[bot] avatar Apr 16 '22 07:04 stale[bot]

The fact that you mention that lowering the language version to below 1.5 makes me think this is due to the change introduced in 1.5.0 about SAM interfaces: https://kotlinlang.org/docs/whatsnew15.html#sam-adapters-via-invokedynamic

Raibaz avatar Apr 16 '22 20:04 Raibaz

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.

stale[bot] avatar Jul 10 '22 20:07 stale[bot]