119

I want to mock a static method m1 from a class which contains 2 static methods, m1 and m2. And I want the method m1 to return an object.

I tried the following

1)

PowerMockito.mockStatic(Static.class, new Answer<Long>() {
         @Override
         public Long answer(InvocationOnMock invocation) throws Throwable {
            return 1000l;
         }
      });

This is calling both m1 and m2, which has a different return type, so it gives a return type mismatch error.

2) PowerMockito.when(Static.m1(param1, param2)).thenReturn(1000l); But this is not called when m1 is executed.

3) PowerMockito.mockPartial(Static.class, "m1"); Gives compiler error that mockPartial not available, which I got from http://code.google.com/p/powermock/wiki/MockitoUsage.

kurtzbot
  • 512
  • 6
  • 19
user1393653
  • 1,191
  • 2
  • 8
  • 3

1 Answers1

162

What you want to do is a combination of part of 1 and all of 2.

You need to use the PowerMockito.mockStatic to enable static mocking for all static methods of a class. This means make it possible to stub them using the when-thenReturn syntax.

But the 2-argument overload of mockStatic you are using supplies a default strategy for what Mockito/PowerMock should do when you call a method you haven't explicitly stubbed on the mock instance.

From the javadoc:

Creates class mock with a specified strategy for its answers to interactions. It's quite advanced feature and typically you don't need it to write decent tests. However it can be helpful when working with legacy systems. It is the default answer so it will be used only when you don't stub the method call.

The default default stubbing strategy is to just return null, 0 or false for object, number and boolean valued methods. By using the 2-arg overload, you're saying "No, no, no, by default use this Answer subclass' answer method to get a default value. It returns a Long, so if you have static methods which return something incompatible with Long, there is a problem.

Instead, use the 1-arg version of mockStatic to enable stubbing of static methods, then use when-thenReturn to specify what to do for a particular method. For example:

import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

class ClassWithStatics {
  public static String getString() {
    return "String";
  }

  public static int getInt() {
    return 1;
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStatics.class)
public class StubJustOneStatic {
  @Test
  public void test() {
    PowerMockito.mockStatic(ClassWithStatics.class);

    when(ClassWithStatics.getString()).thenReturn("Hello!");

    System.out.println("String: " + ClassWithStatics.getString());
    System.out.println("Int: " + ClassWithStatics.getInt());
  }
}

The String-valued static method is stubbed to return "Hello!", while the int-valued static method uses the default stubbing, returning 0.

Tom Tresansky
  • 19,364
  • 17
  • 93
  • 129
  • 1
    Is theren't any need of replay ? – Balaji Boggaram Ramanarayan Dec 11 '14 at 21:19
  • Hmm... sorta seems like so. Maybe PowerMockito does the PowerMock replay for you? I also wonder about that. – djangofan Oct 26 '15 at 20:53
  • 3
    But what if i need to be sure that some static method gets called with precise arguments? – elTomato Jan 28 '16 at 09:18
  • @el_tomato - My example only had no-arg methods, but you would use matchers as usual. See: http://docs.mockito.googlecode.com/hg/latest/org/mockito/Matchers.html – Tom Tresansky Feb 01 '16 at 20:01
  • was the method `mockStatic(Class.type)` removed from the latest version https://github.com/powermock/powermock/blob/release/1.x/powermock-api/powermock-api-mockito/src/main/java/org/powermock/api/mockito/PowerMockito.java – rd22 Aug 31 '17 at 06:32
  • 11
    The `@PrepareForTest` annotation should be the class that *calls* the static method, not the class where the static method is. – Hazel T Dec 04 '17 at 20:35
  • It doesnt work for me, seems like it doesnt detect it as a mock, any ideas? – jpganz18 Oct 19 '18 at 11:27
  • 12
    @HazelTroost - No, the OP is right. It is the class containing the static method that should be prepared for test. So, `@PrepareForTest(ClassWithStatics.class)` is right. – arry36 Jul 18 '19 at 08:08
  • My bad. It's constructor mocking that works like I was saying, not static method mocking. (https://github.com/powermock/powermock/wiki/Mockito#how-to-mock-construction-of-new-objects) – Hazel T Nov 14 '19 at 21:44
  • 3
    Gives me a `MissingMethodInvocationException` – Akshay Hazari Apr 06 '21 at 04:56
  • @TomTresansky, how about static method with parameters, e.g. long or int parameters? – Artanis Zeratul Oct 13 '21 at 00:32
  • @ArtanisZeratul - This should work the same as mocking any method, look into using argumentMatchers. – Tom Tresansky Jun 28 '22 at 19:29
  • This calls the real method while the stubbing is set up, meaning this solution cannot be used if the static method is more complex and has external dependencies (reason for mocking in the first place). Or just simply throws... like replace `return "String";` with `throw new RuntimeException("String");`. – TWiStErRob Mar 08 '23 at 15:18