mockk: Bug[Hard]: "Can't instantiate proxy for class kotlin.Any" when setting up mock on macOS
Prerequisites
Please answer the following questions for yourself before submitting an issue.
- I am running the latest version
- I checked the documentation and found no answer
- I checked to make sure that this issue has not already been filed
Expected Behavior
I have a test case like this:
it("forwards accepted values to all connected ports") {
val port = createDummy()
val connectedPorts = Array(5) {
mockk<StandardPort<Any>>().also { mock ->
every { mock.id } returns "Port $it"
coEvery { mock.accept(any()) } just Runs
port join mock
}
}
// ...
}
I expect that mockk is able to produce mocks that I can use in the rest of the test and make assertions against. I expect this works on all platforms.
Current Behavior
On my Windows development machine this works fine. On my MacBook it throws an exception: io.mockk.MockKException: Can't instantiate proxy for class kotlin.Any
which seems to be caused by the line coEvery { mock.accept(any()) } just Runs
.
Steps to Reproduce
This issue is hard to reproduce. As stated, it only occurs on my MacBook. Additionally, it only occurs when running normally (not debugging). I tried to write another test case to isolate the issue, but it’s strange:
Given this real test case:
it("forwards accepted values to all connected ports") {
val port = createDummy()
val connectedPorts = Array(5) {
mockk<StandardPort<Any>>().also { mock ->
every { mock.id } returns "Port $it"
coEvery { mock.accept(any()) } just Runs
port join mock
}
}
val value = Object()
runBlocking { port.forward(value) }
connectedPorts.forEach {
coVerify(exactly = 1) { it.accept(value) }
}
}
And this dummy test case to try to isolate the problem:
it("temp") {
class Foo {
fun accept(obj: Object): Unit = TODO()
}
val foo = mockk<Foo>()
coEvery { foo.accept(any()) } just Runs
}
I find that:
- if the dummy test case is written above the real test case (and consequently runs first), no issues occur and all test cases pass
- if I write the dummy test case below the real test case, the dummy test case passes and the real test case fails
I noticed in the stacktrace that weakmaps are involved. Seems like some issue with initially populating that map, or maybe because it only holds references weakly something it references gets prematurely GC’d? Might also be a race condition.
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.8.10.kotlin13
- OS: macOS Mojave Version 10.14
- Kotlin version: 1.3.0
- JDK version: 9.0.1 (Oracle Corporation 9.0.1+11)
- JUnit version: jUnit 5
- Type of test: unit test
Stack trace
Running $ gradle clean test --info
, I see this warning included in the output:
com.mycompany.testmaster.domain.StandardPortTests > Scenario: forwards accepted values to all connected ports STANDARD_ERROR
[kotlintest-test-executor-0] WARN io.mockk.proxy.jvm.transformation.InliningClassTransformer - Failed to transform class java/lang/Object
java.lang.NoClassDefFoundError: java/lang/AutoCloseable (wrong name: java/lang/WeakPairMap$Pair$Weak)
at java.base/java.lang.WeakPairMap$Pair.weak(WeakPairMap.java:201)
at java.base/java.lang.WeakPairMap.putIfAbsent(WeakPairMap.java:123)
at java.base/java.lang.Module.implAddReads(Module.java:396)
at java.base/java.lang.Module.implAddReads(Module.java:357)
at java.base/java.lang.System$2.addReads(System.java:2146)
at java.base/jdk.internal.module.Modules.addReads(Modules.java:85)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.lambda$getDynamicModule$4(Proxy.java:884)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.getDynamicModule(Proxy.java:875)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.mapToModule(Proxy.java:814)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:631)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:636)
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$0(Proxy.java:415)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203)
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:413)
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:999)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:305)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:303)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.reflect.annotation.AnnotationParser.annotationForMap(AnnotationParser.java:303)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:293)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.base/java.lang.reflect.Executable.declaredAnnotations(Executable.java:605)
at java.base/java.lang.reflect.Executable.declaredAnnotations(Executable.java:603)
at java.base/java.lang.reflect.Executable.getDeclaredAnnotations(Executable.java:591)
at java.base/java.lang.reflect.Constructor.getDeclaredAnnotations(Constructor.java:579)
at net.bytebuddy.description.method.MethodDescription$ForLoadedConstructor.getDeclaredAnnotations(MethodDescription.java:956)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:732)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:349)
at net.bytebuddy.description.method.MethodList$AbstractBase.asTokenList(MethodList.java:53)
at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default$1.represent(InstrumentedType.java:317)
at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:716)
at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:691)
at io.mockk.proxy.jvm.transformation.InliningClassTransformer.transform(InliningClassTransformer.kt:70)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:157)
at io.mockk.proxy.jvm.transformation.InlineInstrumentation.execute(InlineInstrumentation.kt:39)
at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30)
at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:34)
at io.mockk.impl.instantiation.AbstractMockFactory.newProxy$default(AbstractMockFactory.kt:28)
at io.mockk.impl.instantiation.AbstractMockFactory.mockk(AbstractMockFactory.kt:53)
at com.mycompany.testmaster.domain.StandardPortTests$1$1$6.invoke(StandardPortTests.kt:140)
at com.mycompany.testmaster.domain.StandardPortTests$1$1$6.invoke(StandardPortTests.kt:15)
at io.kotlintest.runner.jvm.TestCaseExecutor$executeTestSet$$inlined$map$lambda$1.call(TestCaseExecutor.kt:104)
at io.kotlintest.runner.jvm.TestCaseExecutor$executeTestSet$$inlined$map$lambda$1.call(TestCaseExecutor.kt:23)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.base/java.lang.Thread.run(Thread.java:844)
Followed later by the stacktrace of the failing test:
com.mycompany.testmaster.domain.StandardPortTests > Describe: Standard port FAILED
io.mockk.MockKException: Can't instantiate proxy for class kotlin.Any
at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:64)
at io.mockk.impl.instantiation.AbstractMockFactory.newProxy$default(AbstractMockFactory.kt:28)
at io.mockk.impl.instantiation.AbstractMockFactory.mockk(AbstractMockFactory.kt:53)
at io.mockk.impl.stub.MockKStub$childMockK$$inlined$synchronized$lambda$1$1.invoke(MockKStub.kt:142)
at io.mockk.impl.stub.MockKStub$childMockK$$inlined$synchronized$lambda$1$1.invoke(MockKStub.kt:8)
at io.mockk.impl.InternalPlatform.customComputeIfAbsent(InternalPlatform.kt:44)
at io.mockk.impl.stub.MockKStub$childMockK$$inlined$synchronized$lambda$1.invoke(MockKStub.kt:141)
at io.mockk.impl.recording.CommonCallRecorder.safeExec(CommonCallRecorder.kt:66)
at io.mockk.impl.log.SafeToString.exec(SafeToString.kt:10)
at io.mockk.impl.stub.MockKStub.childMockK(MockKStub.kt:140)
at io.mockk.impl.recording.PermanentMocker.permamentize(PermanentMocker.kt:48)
at io.mockk.impl.recording.PermanentMocker.mock(PermanentMocker.kt:24)
at io.mockk.impl.recording.states.RecordingState.mockPermanently(RecordingState.kt:120)
at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:32)
at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:45)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:47)
at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:25)
at io.mockk.MockKDsl.internalCoEvery(API.kt:99)
at io.mockk.MockKKt.coEvery(MockK.kt:115)
at com.mycompany.testmaster.domain.StandardPortTests$1$1$6.invoke(StandardPortTests.kt:47)
at com.mycompany.testmaster.domain.StandardPortTests$1$1$6.invoke(StandardPortTests.kt:15)
Caused by:
io.mockk.proxy.MockKAgentException: Failed to subclass class java.lang.Object
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:38)
at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:34)
... 20 more
Caused by:
java.lang.IllegalArgumentException: Could not create type
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:139)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:159)
at io.mockk.proxy.jvm.transformation.SubclassInstrumentation.subclass(SubclassInstrumentation.kt:46)
at io.mockk.proxy.jvm.ProxyMaker.subclass(ProxyMaker.kt:110)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:35)
... 21 more
Caused by:
java.lang.NoClassDefFoundError: java/lang/AutoCloseable (wrong name: java/lang/WeakPairMap$Pair$Weak)
at java.base/java.lang.WeakPairMap$Pair.weak(WeakPairMap.java:201)
at java.base/java.lang.WeakPairMap.putIfAbsent(WeakPairMap.java:123)
at java.base/java.lang.Module.implAddReads(Module.java:396)
at java.base/java.lang.Module.implAddReads(Module.java:357)
at java.base/java.lang.System$2.addReads(System.java:2146)
at java.base/jdk.internal.module.Modules.addReads(Modules.java:85)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.lambda$getDynamicModule$4(Proxy.java:884)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.getDynamicModule(Proxy.java:875)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.mapToModule(Proxy.java:814)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:631)
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:636)
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$0(Proxy.java:415)
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327)
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203)
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:413)
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:999)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:305)
at java.base/sun.reflect.annotation.AnnotationParser$1.run(AnnotationParser.java:303)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.reflect.annotation.AnnotationParser.annotationForMap(AnnotationParser.java:303)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:293)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
at java.base/sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
at java.base/java.lang.reflect.Executable.declaredAnnotations(Executable.java:605)
at java.base/java.lang.reflect.Executable.declaredAnnotations(Executable.java:603)
at java.base/java.lang.reflect.Executable.getDeclaredAnnotations(Executable.java:591)
at java.base/java.lang.reflect.Constructor.getDeclaredAnnotations(Constructor.java:579)
at net.bytebuddy.description.method.MethodDescription$ForLoadedConstructor.getDeclaredAnnotations(MethodDescription.java:956)
at net.bytebuddy.description.method.MethodDescription$TypeSubstituting.getDeclaredAnnotations(MethodDescription.java:1423)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:732)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:349)
at net.bytebuddy.description.method.MethodList$AbstractBase.asTokenList(MethodList.java:53)
at net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy$Default$5.doExtractConstructors(ConstructorStrategy.java:160)
at net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy$Default.extractConstructors(ConstructorStrategy.java:179)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.applyConstructorStrategy(SubclassDynamicTypeBuilder.java:204)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:179)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:172)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3121)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:3258)
at io.mockk.proxy.jvm.transformation.SubclassInstrumentation.doInterceptedSubclassing(SubclassInstrumentation.kt:79)
at io.mockk.proxy.jvm.transformation.SubclassInstrumentation.access$doInterceptedSubclassing(SubclassInstrumentation.kt:17)
at io.mockk.proxy.jvm.transformation.SubclassInstrumentation$subclass$1.call(SubclassInstrumentation.kt:49)
at io.mockk.proxy.jvm.transformation.SubclassInstrumentation$subclass$1.call(SubclassInstrumentation.kt:17)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:137)
... 25 more
// -----------------------[ GRADLE DEFINITIONS ] -----------------------
Root project definitions:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.3.0" apply false
kotlin("kapt") version "1.3.0" apply false
id("org.jlleitschuh.gradle.ktlint") version "6.2.0" apply false
id("com.adarshr.test-logger") version "1.5.0"
`build-scan`
}
allprojects {
group = "com.mycompany.testmaster"
version = "0.1.0"
repositories {
jcenter()
mavenCentral()
}
}
subprojects {
apply(plugin = "org.jlleitschuh.gradle.ktlint")
apply(plugin = "com.adarshr.test-logger")
tasks.withType<Test> {
useJUnitPlatform()
testLogging {
events("PASSED", "FAILED", "SKIPPED")
}
testlogger {
setTheme("mocha")
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
}
buildScan {
setTermsOfServiceUrl("https://gradle.com/terms-of-service")
setTermsOfServiceAgree("yes")
setAllowUntrustedServer(true)
}
Sub-project definitions:
plugins {
kotlin("jvm")
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0")
implementation("io.github.microutils:kotlin-logging:1.6.10")
testImplementation("io.kotlintest:kotlintest-runner-junit5:3.1.9")
testImplementation("io.mockk:mockk:1.8.10.kotlin13")
testImplementation("org.slf4j:slf4j-api:1.7.25")
testImplementation("org.slf4j:slf4j-simple:1.7.25")
}
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 19
Commits related to this issue
- Adding preload of WeakHashMap #168 — committed to mockk/mockk by oleksiyp 6 years ago
Oh thanks. What are the suggested workarounds?
@IgorGanapolsky I got the same error when I tried to mock a String, so instead of
returns mockk()
I didreturns ""
on a function which has String as return typeIt happens again in version 1.13.4. These are the error logs. For me, it doesn’t happen all the time. Only when I run the test repeatedly more than 100 times.
@IgorGanapolsky Strings in JDK are not mockable via any framework. They are very deeply integrated into JDK
I ran into this issue on Android tests (but only when running an entire suite/package of tests), as well as the error
java.lang.ClassNotFoundException: java.lang.Object_Proxy
. However, I am still on 1.9 formockk-android
because upgrading it breaks android tests that are using Mockito 😢 . Is it possible whatever preloading you added to fix this might have interfered with whatever preloading mockito is doing? Is there any global bytebuddy state they are both sharing?