Is it possible to mock a static method in a final class using PowerMockRule instead of PowerMockRunner?

According to PowerMock docs , I have to work with PowerMockRule instead of @RunWith(PowerMockRunner.class) and get the same results.

I seem to have found a case where this is not true.

An example is shown below:

 package com.test.powermockstatics; import static org.junit.Assert.assertEquals; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; final class FinalClassWithStaticCall { public static int getIntStatic() { return 1; } } @RunWith(PowerMockRunner.class) @PrepareForTest(FinalClassWithStaticCall.class) public class TestStaticMockingWithoutPowerMockRunner { @Test public void testStaticCall() { mockStatic(FinalClassWithStaticCall.class); when(FinalClassWithStaticCall.getIntStatic()).thenReturn(2); assertEquals(FinalClassWithStaticCall.getIntStatic(), 2); } } 

But when switching to such a rule:

 package com.test.powermockstatics; import static org.junit.Assert.assertEquals; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; import org.junit.Rule; import org.junit.Test; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.agent.PowerMockAgent; import org.powermock.modules.junit4.rule.PowerMockRule; final class FinalClassWithStaticCall { public static int getIntStatic() { return 1; } } @PrepareForTest(FinalClassWithStaticCall.class) public class TestStaticMockingWithoutPowerMockRunner { static { PowerMockAgent.initializeIfNeeded(); } @Rule public PowerMockRule rule = new PowerMockRule(); @Test public void testStaticCall() { mockStatic(FinalClassWithStaticCall.class); when(FinalClassWithStaticCall.getIntStatic()).thenReturn(2); assertEquals(FinalClassWithStaticCall.getIntStatic(), 2); } } 

I get the following exception:

java.lang.IllegalArgumentException: cannot subclass the final class class com.test.powermockstatics.FinalClassWithStaticCall at org.mockito.cglib.proxy.Enhancer.generateClass (Enhancer.java-00-0047) in org.mockito.cglib.core.DefaultGenerator.graterator.graterator (DefaultGeneratorStrategy.java:25) at org.mockito.cglib.core.AbstractClassGenerator.create (AbstractClassGenerator.java:217) at org.mockito.cglib.proxy.Enhancer.createHelper (Enhancer.javahaps78) at org.mockito. cglib.proxy.Enhancer.createClass (Enhancer.javahaps18) in org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass (ClassImposterizer.java:110) in org.mockito.internal.creation.jmock.ClassImposterizer.imposter ClassImposterizer.java:62) in org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl (MockCreator.java:111) in org.powermock.api.mockito.internal.mockcreation.MockCreator.mock (MockCreator.mock 60) at org.powermock.api.mockito.P owerMockito.mockStatic (PowerMockito.java:70) in com.test.powermockstatics.TestStaticMockingWithoutPowerMockRunner.testStaticCall (TestStaticMockingWithoutPowerMockRunner.java:30) at sun.reflect.NativeMethodAccessorImplinative.plorlectlative.ethorativeflect.notative.plorlectlativeflect.notative.plorlectlative.thorativeflect.notative.plorlectlative.ethorativepl.nativemethinativefth.nativeflect.notative.plorlectlative.notative.plf.nativefunction.ltative.ethorativepl.notative.plf.nativefunction java: 57) in sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) in java.lang.reflect.Method.invoke (Method.java:606) in org.junit.runners.model.FrameworkMethod $ 1.runReflective FrameworkMethod.java:47) in org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:12) in org.junit.runners.model.FrameworkMethod.invokeExplosively (FrameworkMethod.java:44) in org.junit .internal.runners.statements.InvokeMethod.evaluate (InvokeMethod.java:17) at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate (PowerMockRule.java:49) at org.junit.runners.ParentRunner.runLafaf .java: 271) in org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:50) at org.junRunner.ununrunnernernernernernernernernernernernernernernernernernernerunner tuner ) at org.junit.runners.ParentRunner $ 1.schedule (ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren (ParentRunner.java:236) at org.junit.runners.ParentRunner.access $ 000 (ParentRunner. java: 53) in org.junit.runners.ParentRunner $ 2.valuation (ParentRunner.java:229) in org.junit.runners.ParentRunner.run (ParentRunner.java.309) in org.eclipse.jdt.internal.junit4. runner.JUnit4TestReference.run (JUnit4TestReference.java:50) in org.eclipse.jdt.internal.junit.runner.TestExecution.run (TestExecution.java:38) in org.eclipse.jdt.internal.junit.runestRnernerTem runTests (RemoteTestRunner.java:467) in org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests (RemoteTestRunner.java:683) in org.eclipse.jdt.internal.junit.runner.RemoteT estRunner.run (RemoteTestRunner.java//90) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main (RemoteTestRunner.java:197)

I follow the recommendations from the docs:

put the powermock-module-junit4-rule-agent agent before junit in the Classpath

Does anyone know the official word if this is a mistake in PowerMock or the desired behavior (i.e. you just can’t mock the static method in the final class using PowerMockRule )?

EDIT:

Please read the explanation in the comments in response to Gabor Liptak . I do not want to use a statically loaded agent, since it seems that a dynamically loaded agent should be able to do the job?

I know that starting an agent will statically work. (Unfortunately, this is not an option in my project.) So, does anyone know if a dynamically loaded agent crashes in PowerMock? Or a known limitation; and why?

+7
junit mockito powermock junit-rule junit-runner
source share
3 answers

You need to prepare a class for testing!

@PrepareForTest(MyFinalClass.class )

+15
source share

To mock the final classes, the classpath is not enough. You need a JVM agent.

According to docs :

In some cases (for example, mocking end classes), you may need to load the PowerMock agent eagerly into Maven for the tests to work in Surefire. If you are experiencing this, add the following: your pom.xml:

Required JVM argument for modeling final classes:

 -javaagent:${settings.localRepository}/org/powermock/powermock-module-javaagent/1.5.6/powermock-module-javaagent-1.5.6.jar 
+1
source share

I had the same symptom, and I was able to solve it by expanding the test class from PowerMockTestCase.

 public class NetworkManagerUtilsTest extends PowerMockTestCase { 

Not sure if this solution is applicable here.

+1
source share

All Articles