Robolectric + PowerMock + Mockito not working
Asked Answered
D

1

10

I'm struggling to get this rare combination works, but I haven't got luck. My project uses JUnit + Mockito + Robolectric for testing and Roboguice for injection, when I added PowerMock to the equation weird things happened, this are some of the things I've tried:

1.- Out of the box PowerMock + Mockito + Robolectic integration. As suggested on PowerMockIngration, I added a @PowerMockRunnerDelegate to include my custom runner which extends from RobolectricGradleTestRunner:

Build.gradle

  testCompile 'org.powermock:powermock-module-junit4:1.6.4'
  testCompile 'org.powermock:powermock-api-mockito:1.6.4'

Test

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(MyCustomRunner.class)
@Config(constants = BuildConfig.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest(RoboGuice.class)
public class Test {

  @Before
  public void setUp() throws Exception {
    PowerMockito.mockStatic(RoboGuice.class);
    ....
  }

Result:

java.lang.IllegalArgumentException: Cannot subclass final class class roboguice.RoboGuice at org.mockito.cglib.proxy.Enhancer.generateClass(Enhancer.java:447) 
 at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
    at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
    at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
    at org.powermock.api.mockito.repackaged.ClassImposterizer.createProxyClass(ClassImposterizer.java:123)
    at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:57)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:111)
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:59)
    at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:70)
    at com.humana.vitalityapp.activity.BaseVitalityActivityTest.setUp(BaseVitalityActivityTest.java:79)
    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:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
    at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
    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.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:146)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:139)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.withContextClassLoader(DelegatingPowerMockRunner.java:130)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:139)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)...

So is like @PrepareForTest is nor working, then I tried when a rule a class loader, as suggested in the same guide:

Build.gradle

  testCompile 'org.powermock:powermock-module-junit4:1.6.4'
  testCompile "org.powermock:powermock-module-junit4-rule:1.6.4"
  testCompile 'org.powermock:powermock-api-mockito:1.6.4'
  testCompile "org.powermock:powermock-classloading-xstream:1.6.4"

Test Class

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(MyCustomRunner.class)
@Config(constants = BuildConfig.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest(RoboGuice.class)
public class Test { 
  @Rule public PowerMockRule rule = new PowerMockRule();

@Before
  public void setUp() throws Exception {
    PowerMockito.mockStatic(RoboGuice.class);
   ...
  }

At this point the test passes and I was able to mock RoboGuice as expected, BUT when I ran all my test cases together I start getting the following exception when creating a simple mock like mock(OtherClass.class):

org.mockito.exceptions.base.MockitoException: 
ClassCastException occurred while creating the mockito proxy :
  class to mock : 'com.humana.vitalityapp.analytics.Analytics', loaded by classloader : 'org.powermock.core.classloader.MockClassLoader@168fa63d'
  created class : 'com.humana.vitalityapp.analytics.Analytics$$EnhancerByMockitoWithCGLIB$$67cb81b1', loaded by classloader : 'org.mockito.internal.creation.util.SearchingClassLoader@20f5a6b6'
  proxy instance class : 'com.humana.vitalityapp.analytics.Analytics$$EnhancerByMockitoWithCGLIB$$67cb81b1', loaded by classloader : 'org.robolectric.internal.bytecode.InstrumentingClassLoader@6fdbe764'
  instance creation by : ObjenesisInstantiator

You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)

    at com.humana.vitalityapp.activity.BaseVitalityActivityTest.setUp(BaseVitalityActivityTest.java:77)
    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:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:65)
    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:497)

So I tried a lots of variants: Remove the xtream class loader:

  java.lang.RuntimeException: java.lang.ClassNotFoundException: org.powermock.classloading.DeepCloner

    at org.powermock.api.support.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:68)
    at org.powermock.api.support.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:34)

User JunitAgent:

 testCompile 'org.powermock:powermock-module-junit4:1.6.4'
  testCompile "org.powermock:powermock-module-junit4-rule-agent:1.6.4"
  testCompile 'org.powermock:powermock-api-mockito:1.6.4'

Caused by: java.lang.IllegalStateException: PowerMockRule can only be used with the system classloader but was loaded by org.robolectric.internal.bytecode.InstrumentingClassLoader@2a7f1f10

So I running out of ideas, anyone??

Dravidian answered 22/3, 2016 at 14:26 Comment(7)
Great effort to make this setup working. Fortunately, I'm not big fun on PowerMock, so I don't use it. Unfortunately, I also don't know how to make it working. Is it recommended way of testing RoboGuice things?Predictor
Well, I'm only adding a new BaseActivity for my project because I'm updating to use AppCompat, so my new activity extends from it, and I'm trying to inject everything on it, and its working, I just wanted to test that class, the other way I tried is wrapping RoboGuice.getInjector in a provider, in that way I could test everything, I was just trying to use PowerMock to avoid creating providers for static class, since form me it loose the advantages of static methodsDravidian
Can you try recommended way? In this case you don't need powermockPredictor
With "recommended way", do you mean adding a provider? If thats the case, yes I did it and its working I was just trying to setup PowerMock to mock static methods across the app, the issue is the same when you have a final class and tries to mock it and use the PowerMock/RobolectricRunner togetherDravidian
Aha, I should be more focused. What static call you're trying to mock? Maybe there is another way of testing it. With provider you don't need to mock RoboGuice statically, correct?Predictor
Yes thats right, because I can inject or set the provider and stub it as a regular class using Mockito, but at least for me I like to use static methods when I can.Dravidian
I would argue, but this is a matter of taste. Static always makes testing harder or code vulnerable for the modifcationsPredictor
T
0

I had the same problem.

My solution was to:

  • remove testCompile "org.powermock:powermock-module-junit4-rule-agent:x.x.x" from gradle

  • change import static *.Mockito.mock and *.Mockito.when to org.powermock.api.mockito.PowerMockito.mock and org.powermock.api.mockito.PowerMockito.when.

Teodoor answered 6/12, 2017 at 9:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.