Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spayk on a interface object gets java.lang.IncompatibleClassChangeError, and failed #804

Open
lannyf77 opened this issue Mar 16, 2022 · 4 comments

Comments

@lannyf77
Copy link

when spy on a interface object, it got

WARNING: Failed to transform class com/module/EvntHandleTest$test_evtListener$1$listener$1
java.lang.IncompatibleClassChangeError: 

the class:

///
open class TestClass(internal var mListener: EventListener?) {
    fun interface EventListener {
        fun onEvent(eventType: String, data: String): Boolean;
    }

    fun doSomething(eventType: String, data: String) {
        callListener(eventType, data)
    }

    internal fun callListener(eventType: String, data: String): Boolean {
        mListener?.let {
            return it.onEvent(eventType, data)
        }
        return false
    }
}
///

// test

@RunWith(AndroidJUnit4::class)
class EvntHandleTest {

    @Test
    fun test_evtListener() {
        io.mockk.mockkStatic(android.util.Log::class) {
            var listenerCalled = true
            val listener = object : TestClass.EventListener {
                override fun onEvent(eventType: String, data: String): Boolean {
                    android.util.Log.i("EventListener", eventType)
                    listenerCalled = false
                    return listenerCalled
                        .also {
                            System.out.println("+++ +++ onEvent($eventType: String, $data: Any)")
                        }
                }
            }

            val listenerSpy = io.mockk.spyk(listener)
            val testClass = TestClass(listenerSpy)
            testClass.doSomething("theType", "eee888")

            io.mockk.verify(exactly = 1) {
                listenerSpy.onEvent(any(), any())
            }

            io.mockk.verify(exactly = 1) {
                Log.i(eq("EventListener"), eq("theType"))
            }
            assert(!listenerCalled)
        }
    }
}

test output:

[Robolectric] com.module.EvntHandleTest.test_evtListener: sdk=28; resources=BINARY
Called loadFromPath(/system/framework/framework-res.apk, true); mode=binary sdk=28
Mar 16, 2022 10:34:07 AM io.mockk.impl.log.JULLogger warn
WARNING: Failed to transform class com/module/EvntHandleTest$test_evtListener$1$listener$1
java.lang.IncompatibleClassChangeError: com.module.aEvntHandleTest and com.module.EvntHandleTest$test_evtListener$1$listener$1 disagree on InnerClasses attribute
	at java.lang.Class.getDeclaringClass0(Native Method)
	at java.lang.Class.getDeclaringClass(Class.java:1235)
	at net.bytebuddy.description.type.TypeDescription$Generic$OfNonGenericType$ForLoadedType.getOwnerType(TypeDescription.java:3981)
	at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor$ForDetachment.onSimpleType(TypeDescription.java:2059)
	at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor.onNonGenericType(TypeDescription.java:1880)
	at net.bytebuddy.description.type.TypeDescription$Generic$Visitor$Substitutor$ForDetachment.onNonGenericType(TypeDescription.java:2022)
	at net.bytebuddy.description.type.TypeDescription$Generic$OfNonGenericType.accept(TypeDescription.java:3783)
	at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:807)
	at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:373)
	at net.bytebuddy.description.method.MethodList$AbstractBase.asTokenList(MethodList.java:87)
	at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default$1.represent(InstrumentedType.java:415)
	at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:782)
	at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:757)
	at io.mockk.proxy.jvm.transformation.InliningClassTransformer.transform(InliningClassTransformer.kt:71)
	at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
	at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
	at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
	at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
	at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28)
	at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:19)
	at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:6)
	at io.mockk.proxy.common.transformation.ClassTransformationSpecMap.applyTransformation(ClassTransformationSpecMap.kt:41)
	at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation.execute(RetransformInlineInstrumnetation.kt:16)
	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:29)
	at io.mockk.impl.instantiation.AbstractMockFactory.spyk(AbstractMockFactory.kt:102)
	at com.module.EvntHandleTest.test_evtListener(PsaEvntHandleTest.kt:211)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:546)
	at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

+++ +++ onEvent(theType: String, eee888: Any)
+++ +++ onEvent(-3089f9b3d46541dd: String, 58cb97533a779e3d: Any)

io.mockk.MockKException: Failed matching mocking signature for
SignedCall(retValue=0, isRetValueMock=false, retType=class kotlin.Int, self=class android.util.Log, method=i(String, String), args=[EventListener, -3089f9b3d46541dd], invocationStr=class android.util.Log.i(EventListener, -3089f9b3d46541dd))
left matchers: [any()]

	at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:99)
	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:63)
	at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30)
	at io.mockk.MockKDsl.internalVerify(API.kt:118)
	at io.mockk.MockKKt.verify(MockK.kt:149)
	at io.mockk.MockKKt.verify$default(MockK.kt:146)
	at com.module.PsaEvntHandleTest.test_evtListener(PsaEvntHandleTest.kt:71)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:546)
	at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

having

            compilesdk   : 30,
            targetsdk    : 30,
            buildtools   : '29.0.2',
            supportlib   : '28.0.0',

            robolectric  : "4.3.1", 
            junitVersion : "4.13.2",
          
            mockkVersion : "1.11.0"
    

using android studio 4.1.2, with JDK JAVA_VERSION="1.8.0_242" for the Gradle

@Raibaz
Copy link
Collaborator

Raibaz commented Mar 24, 2022

I don't think you can spyk an interface, since spies try to execute the actual methods of the objects being spied, it's probably better to mockk it.

@lannyf77
Copy link
Author

@Raibaz are you refereeing the io.mockk.spyk(listener), which spyk on an object who implements the interface?

val listener = object : TestClass.EventListener {
                override fun onEvent(eventType: String, data: String): Boolean {
                    android.util.Log.i("EventListener", eventType)
                    listenerCalled = false
                    return listenerCalled
                        .also {
                            System.out.println("+++ +++ onEvent($eventType: String, $data: Any)")
                        }
                }
            }

            val listenerSpy = io.mockk.spyk(listener)

@stale
Copy link

stale bot commented Jul 10, 2022

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 stale bot added the stale label Jul 10, 2022
@beachcitiessoftware
Copy link

This is still happening. Please add the important label.

@stale stale bot removed the stale label May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants