powermock icon indicating copy to clipboard operation
powermock copied to clipboard

Mockito mock-maker-inline does not work with Robolectric

Open manuelvicnt opened this issue 7 years ago • 5 comments

PowerMock is supposed to solve the integration problem with Mockito mock-maker-inline. However, since it uses its custom PowerMockMaker, it cannot initialize Byte Buddy mock maker.

The problem is this one: "This mock maker is not supported on Android" when running side by side with Robolectric. It seems like Robolectric already solved this issue here: https://github.com/robolectric/robolectric/pull/2761

Caused by: org.mockito.exceptions.base.MockitoInitializationException: 
Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)

Libraries used: mockitoVersion -> 2.8.9 powermockVersion -> 1.7.0 robolectricVersion -> 3.4-rc2

When you try to mock a simple final class with the JUnit4 or PowerMock runners you can see this error:

java.lang.RuntimeException: Invoking the beforeTestMethod method on PowerMock test listener org.powermock.api.extension.listener.AnnotationEnabler@4229bb3f failed.

	at org.powermock.tests.utils.impl.PowerMockTestNotifierImpl.notifyBeforeTestMethod(PowerMockTestNotifierImpl.java:84)
	at org.powermock.modules.junit4.internal.impl.NotificationBuilder$OngoingTestRun.<init>(NotificationBuilder.java:90)
	at org.powermock.modules.junit4.internal.impl.NotificationBuilder.testStartHasBeenFired(NotificationBuilder.java:233)
	at org.powermock.modules.junit4.internal.impl.PowerMockRunNotifier.fireTestStarted(PowerMockRunNotifier.java:112)
	at org.junit.internal.runners.model.EachTestNotifier.fireTestStarted(EachTestNotifier.java:42)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:323)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:149)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:141)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.withContextClassLoader(DelegatingPowerMockRunner.java:132)
	at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:141)
	at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
	at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
	at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
	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 com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)
Caused by: java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker
	at org.mockito.internal.configuration.plugins.PluginLoader$1.invoke(PluginLoader.java:66)
	at com.sun.proxy.$Proxy14.createMock(Unknown Source)
	at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:116)
	at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMock(DefaultMockCreator.java:69)
	at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.mock(DefaultMockCreator.java:46)
	at org.powermock.api.mockito.PowerMockito.mock(PowerMockito.java:192)
	at org.powermock.api.extension.listener.AnnotationEnabler.standardInject(AnnotationEnabler.java:107)
	at org.powermock.api.extension.listener.AnnotationEnabler.beforeTestMethod(AnnotationEnabler.java:55)
	at org.powermock.tests.utils.impl.PowerMockTestNotifierImpl.notifyBeforeTestMethod(PowerMockTestNotifierImpl.java:82)
	... 30 more
Caused by: java.lang.IllegalStateException: Failed to load interface org.mockito.plugins.MockMaker implementation declared in sun.misc.CompoundEnumeration@73ee04c8
	at org.mockito.internal.configuration.plugins.PluginLoader.loadImpl(PluginLoader.java:101)
	at org.mockito.internal.configuration.plugins.PluginLoader.loadPlugin(PluginLoader.java:45)
	at org.mockito.internal.configuration.plugins.PluginRegistry.<init>(PluginRegistry.java:18)
	at org.mockito.internal.configuration.plugins.Plugins.<clinit>(Plugins.java:17)
	at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.getMockMaker(DefaultMockCreator.java:140)
	at org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator.createMethodInvocationControl(DefaultMockCreator.java:99)
	... 36 more
Caused by: java.lang.IllegalStateException: Failed to load MockMaker implementation: org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker
	at org.powermock.api.mockito.mockmaker.MockMakerLoader.load(MockMakerLoader.java:39)
	at org.powermock.api.mockito.mockmaker.PowerMockMaker.<init>(PowerMockMaker.java:45)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.mockito.internal.configuration.plugins.PluginLoader.loadImpl(PluginLoader.java:96)
	... 41 more
Caused by: org.mockito.exceptions.base.MockitoInitializationException: 
Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)

Java               : 1.8
JVM vendor name    : JetBrains s.r.o
JVM vendor version : 25.112-b736
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 1.8.0_112-release-b736
JVM info           : mixed mode
OS name            : Mac OS X
OS version         : 10.12.5

	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.<init>(InlineByteBuddyMockMaker.java:172)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.powermock.api.mockito.mockmaker.MockMakerLoader.load(MockMakerLoader.java:36)
	... 48 more
Caused by: java.lang.IllegalStateException: Error during attachment using: net.bytebuddy.agent.ByteBuddyAgent$AttachmentProvider$Compound@55607a32
	at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:379)
	at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:353)
	at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:321)
	at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:307)
	at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.<clinit>(InlineByteBuddyMockMaker.java:102)
	... 54 more
Caused by: java.lang.reflect.InvocationTargetException
	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 net.bytebuddy.agent.Attacher.install(Attacher.java:78)
	at net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:374)
	... 58 more
Caused by: java.lang.NullPointerException
	at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:182)
	... 64 more

manuelvicnt avatar Jun 16 '17 17:06 manuelvicnt

@xian and @raphw could you help me to clarify the issue and current state with https://github.com/robolectric/robolectric/pull/2761

PowerMock uses the following code to load InlineByteBuddyMockMaker.

        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = ClassLoader.getSystemClassLoader();
        }
        
        String mockMakerClassName = mockitoConfiguration.getMockMakerClass();
        
        try {
            Class<?> mockMakerClass = loader.loadClass(mockMakerClassName);
            Object mockMaker = mockMakerClass.newInstance();
            return MockMaker.class.cast(mockMaker);
        } catch (Exception e) {
            throw new IllegalStateException("Failed to load MockMaker implementation: " + mockMakerClassName, e);
        }

I guess that in this case Robolectric ClassLoader is used and everything should be fine.

I'm not sure, but maybe correct way to load a class will be Class.forName(mockMakerClassName).newInstance()

thekingn0thing avatar Jun 16 '17 18:06 thekingn0thing

The inline Mock maker needs to load a class explicitly as it must inject a type into the bootstrap class loader. I guess some explicit class loading is triggering some code before the inline mock maker is loaded such that this yields a race?

I am however confused over this mistake:

Caused by: java.lang.NullPointerException at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:182)

Could you look at the line in question and debug what is missing? Are you running on a JDK?

raphw avatar Jun 19 '17 22:06 raphw

@raphw,

As I see in stacktrace it was OpenJDK

Java : 1.8 JVM vendor name : JetBrains s.r.o JVM vendor version : 25.112-b736 JVM name : OpenJDK 64-Bit Server VM JVM version : 1.8.0_112-release-b73

thekingn0thing avatar Jun 19 '17 22:06 thekingn0thing

@raphw @thekingnothing Yes, it's OpenJDK because I'm using Robolectric

manuelvicnt avatar Jun 26 '17 16:06 manuelvicnt

did you ever solve this issue?

kassim avatar Dec 04 '20 11:12 kassim