Mocking static methods in Java system classes

As you may already know PowerMock can be used to easily mock static methods which is normally not possible with standard mock frameworks such as EasyMock, JMock or Mockito. All you have to do is to use mockStatic in one of the PowerMock extension API’s as well as telling PowerMock to enable the class for testing using the @PrepareForTest annotation. A simple example of this can be seen below (using the EasyMock extension API):

And the test:

The “power” behind PowerMock lies in its ability to modify the byte-code of the classes specified in the PrepareForTest annotation to make them testable. But because of restrictions enforced by the Java run-time PowerMock is simply not allowed to byte-code manipulate certain classes dynamically. These classes are those that are loaded by Java’s bootstrap class-loader such as for example java.net.URLEncoder, java.lang.System and other “system classes” located in the java.lang or java.net package etc. While is this generally not a problem it may be so if you need to mock static methods in these classes because PowerMock cannot prepare them for test. So how do we get around this problem?

How does PowerMock work?

To start of with we probably should describe how PowerMock actually works under hood. What happens when PowerMock makes a class testable is that the byte-code is changed so that each method call, constructor call, field call etc are first routed to something that we refer to as the MockGateway. Simply put the MockGateway decides if it’s OK for the call to be delegated to the original method/constructor/field or if a mock object should be returned instead. The MockGateway communicates with a MockRepository which stores all mock objects that has been setup for the current test method. Since PowerMock is just a layer on top of other mock frameworks we leave it for the underlying framework to do the actual mock creation, recording and verification of the mocks. The created mocks are put into the MockRepository by the PowerMock mock extension API. Basically all standard mock frameworks use CGLib to create a mock object which means that they’re based on a hierarchical model (CGLib creates a sub class of the class to test at run-time which is the actual mock object) instead of a delegation model which PowerMock uses through it’s byte-code manipulation by delegating to the MockGateway. This means that e.g. if a class is final CGLib cannot create a sub-class of it at run-time and therefore we can’t mock it. So this is why most mock frameworks have the limitations that PowerMock doesn’t.

So how do we mock static methods in a system class?

Since there’s no way for PowerMock to modify the byte-code of a system class how do we route all calls to the MockGateway? The answer is quite simple, don’t modify the system class itself but modify the class calling the system class! Thus outgoing calls to methods in the system class can be routed to the MockGateway instead of the system class intercepting incoming calls. That sounds simple enough but there’s one more catch. As we saw earlier you set up expectations in the EasyMock extension API by reusing the standard expect method, e.g.

and this usually works fine because Greeting has been prepared for test and the call to method getGreeting is routed to the MockGateway. But in cases of system classes a call to a static method is NOT intercepted by the system class itself as described above and thus the call is never routed to the MockGatway. The solution is to prepare the actual test class for test as well so that the outgoing method call to getGreeting in the expect method is routed to the MockGateway as well! So let’s look at a very simple example to demonstrate how to mock a call to URLEncoder.encode(..):

and the test:

But wait, will this work for final system classes?

That’s a really good question because as we said earlier PowerMock delegates the mock creation process to the underlying mock framework (such as EasyMock) which uses CGLib. So even when mocking static methods the underlying mock framework is still used to create the CGLib mock of the class where the static methods are located. PowerMock then make use of the underlying framework’s functionality to hold state for all recorded method invocations etc so that we don’t have to deal with that in PowerMock as well. So usually what PowerMock does when it encounters a final class that should be prepared for test is simply to remove the final modifier. This means that CGLib can be used to create the mock object of this class without any problems. But what about a final system class? There’s no way for PowerMock to remove the final modifier of a system class so what to do? What PowerMock does in these cases is to create a completely new class at run-time with the exact same structure as the original final system class. I.e. all method names and their corresponding signature are copied to a this new replica class. To allow for partial mocking all static methods of the replica class delegates to the original method in the final system class. It’s also the replica class that is being mocked by the underlying mock framework instead of the original system class. The MockGateway then figures out that all methods bound for this particular system class should be routed to the replica mock instead. Thus mocking of static methods in final system classes such as java.lang.System or java.lang.String works as well. As a side note it would actually be possible to use this technique to implement duck-typing in Java as well. Anyway, here’s an example to demonstrate what we’ve just said:

and the test:

Conclusion

As we’ve seen PowerMock is capable of achieving things not normally possible with standard mock frameworks because of technical limitations. Using PowerMock you can virtually choose any design you like without having to worry about the testability (or mockability to be more precise) aspects. Please visit our website for more information and downloads.

23 Comments

  1. Nicholas

    Thanks very much ! :)
    I’ve been looking for this issue for a long time — mocking static method

  2. Sergii Pogodin

    Man, thanks alot for this one.
    Please specify either import statements or full invocation path, i.e. PowerMock.mockStatic(…), EasyMock.expect(…) and so on.
    Coz it’s quite not obvious.

  3. fengguanghui

    Thanks very much ! :)
    I’ve been looking for this issue for a long time — mocking static method

  4. Brahma

    Code Snippet:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest( value = { Util.class, Translator.class,
    TranslatorTest.class })
    public class TranslatorTest extends TestCase {

    public void testGetTranslate() throws Throwable {
    EncryptParams mockEncryptParams = getMockEncryptParams();
    PowerMock.mockStatic(Util.class);
    PowerMock.expectPrivate(Util.class,loadConfig);

    PowerMock.replay(Util.class);

    assertEquals(ASCIITOEBCDIC, Translator.getTranslateType(mockEncryptParams));

    PowerMock.verify(Util.class);
    }

    }

    *** where loadConfig is a private static method in Util.class

    why i am getting the below exception

    java.lang.IllegalStateException: no last call on a mock available
    at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
    at org.easymock.EasyMock.expectLastCall(EasyMock.java:512)
    at org.powermock.api.easymock.PowerMock.doExpectPrivate(PowerMock.java:2247)
    at org.powermock.api.easymock.PowerMock.expectPrivate(PowerMock.java:1409)

  5. Dev_Alf

    Hi, I have problems with ‘final’ attributes.
    I saw your tutorial with ‘final’ classes, but if I have the following situation:

    public final class ClassA {
    public static final String ATTRIBUTE_A= “attA”;
    public static final String ATTRIBUTE_B = “attB”;
    public static String user;
    public static String password;

    }

    How can I do to ‘mock’ these static and final attributes? like this:
    when(ClaseA.user).thenReturn(“admin”);

    Is it possible?

    Thanks! I will wait your answer.

  6. Prajakta

    its a nice an most useful artical

  7. Please use the powermock mailing list to post questions.

  8. Great article! But can you tell me which version of PowerMock is used? I can’t get it to work using version 1.4.10…

  9. Thanks for the reply Johan, but unfortunately I can’t get those examples to work either.
    The framework throws an IllegalArgumentException on the mockStatic(System.class):
    java.lang.IllegalArgumentException: replica.java.lang.System$$PowerMock0 is not an interface
    at java.lang.reflect.Proxy.getProxyClass(Proxy.java:362)
    at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
    at org.easymock.internal.JavaProxyFactory.createProxy(JavaProxyFactory.java:12)
    at org.easymock.internal.MocksControl.createMock(MocksControl.java:37)
    at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2212)
    at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2134)
    at org.powermock.api.easymock.PowerMock.mockStatic(PowerMock.java:287)

    I know this isn’t the place for Q&A but do you have any tips I could try?

    Thanks in advance!

  10. Please continue the conversation on the mailing-list and include an example of the code you’re trying to test as well as your test.

  11. zaghman

    its a great article.i tried to implement the above example but i got an exception
    java.lang.IllegalArgumentException: temp.ClassWithStaticMethod is not an interface
    at java.lang.reflect.Proxy.getProxyClass(Proxy.java:362)
    at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
    at org.easymock.internal.JavaProxyFactory.createProxy(JavaProxyFactory.java:24)
    at org.easymock.internal.MocksControl.createMock(MocksControl.java:51)
    at org.powermock.api.easymock.PowerMock.doCreateMock(PowerMock.java:2212)
    at org.powermock.api.easymock.PowerMock.doMock(PowerMock.java:2163)
    at org.powermock.api.easymock.PowerMock.mockStatic(PowerMock.java:287)
    at temp.MockStaticExampleTest1.MockStaticMethodToReturnSix(MockStaticExampleTest1.java:17)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:307)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:112)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:73)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

    Any help?

  12. Kelly

    Hi There!
    I have been using PowerMock for a little while and thanks it is brilliant! However there is a scenario I keep coming across where I am trying to mock a static method found in a class where there are also static fields.
    Do I really have to use the white box to set the Static fields evertime? This seems a bit long winded.
    Your help would be much appreciated.
    Many Thanks
    Kelly

  13. Marino Borra

    And for mock Calendar.getInstance() ?

    Calendar todayCalendar = PowerMock.createMock( Calendar.class );
    PowerMock.mockStatic( Calendar.class );
    EasyMock.expect( todayCalendar.getTime() ).andReturn( new Date( 2012, 1, 1 ) );
    EasyMock.expect( Calendar.getInstance() ).andReturn( Calendar.getInstance() );
    PowerMock.replayAll();

    boolean isAdult = Person.isTodayAdult( new Date( 1970, 8, 30 ), 18 );

    Assertions.assertThat( isAdult ).isTrue();

    PowerMock.verifyAll();

  14. powder366

    Can’t get PowerMock and Mockito to run. See link:

    http://stackoverflow.com/questions/14983831/powermock-with-mockito

    Help appreciated!

  15. But it is giving error of initializationError

  16. Ashutosh

    Hi Jay,
    I am using powermock. I need to test a class A. It has two static private methods (method1 and method2). Method1 internally calls method2. I am testing method1. But somehow it is failing.

    PowerMock.mockStaticPartial(A.class, “method2”, File.class);
    PowerMock.expectPrivate(A.class, “method2”, mockFileParameter).andReturn((int)0);

    I am getting error with below
    Unexpected method call A.method2(EasyMock for class java.io.File):
    A.method2(EasyMock for class java.io.File): expected: 1, actual: 0

  17. Bryan

    This article should be marked as deprecated. This thing just doesn’t work. I am getting same error as Thomas. Even the examples in https://code.google.com/p/powermock/source/browse/trunk/modules/module-test/easymock/junit4-test/src/test/java/samples/junit4/system/SystemClassUserTest.java are not working. I tried the System.class example.

    Please update the library or mark this thing as deprecated, people should not waste their time here.

    • Johan Haleby

      The tests are run every time I commit something to PowerMock and every time its released so they do work. If you have any problems then please use the mailing list (see the website for details).

Trackbacks for this post

  1. Mocking Statics and java.lang.IllegalStateException: no last call on a mock available | JSF Blog
  2. Mock de métodos estáticos em Java | victor serta /blog
  3. URL
  4. click here

Leave a Reply