I want to mock a static interface method with Powermock. Here's the interface:
public interface IConcurrentUtil {
static void threadSleep(final long millis) {
try {
Thread.sleep(millis);
} catch (final InterruptedException e) {
;
}
}
}
Here's the class which uses threadSleep:
public class ConcurrentUser {
public void callInterfaceMethod() {
IConcurrentUtil.threadSleep(3000L);
}
}
And finally the test class:
@RunWith(PowerMockRunner.class)
@PrepareForTest(ConcurrentUser.class)
@PowerMockIgnore("javax.management.*")
public class ConcurrentUtilsTest {
private ConcurrentUser concurrentUser;
@Before
public void setUp() {
concurrentUser = new ConcurrentUser();
}
@Test
public void testThreadSleepCallsSleepCorrect() throws Exception {
mockStatic(IConcurrentUtil.class);
doNothing().when(IConcurrentUtil.class);
IConcurrentUtil.threadSleep(3000L);
concurrentUser.callInterfaceMethod();
verifyStatic(times(1));
IConcurrentUtil.threadSleep(3000L);
}
}
Powermock gives this error:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:36)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
at org.powermock.api.mockito.PowerMockito.verifyStatic(PowerMockito.java:288)
at com.test.concurrent.ConcurrentUtilsTest.testThreadSleepCallsSleepCorrect(ConcurrentUtilsTest.java:35)
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:483)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
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:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
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:122)
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)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
I'm using PowerMock 1.6.2 and JUnit 4.12.
Are there any special rules or commands which need to be applied when dealing with static(or default) interface methods?
Actually in your case, you do not need to do stubbing, as mockStatic already does this for you, it's just redundant.
So, the following would work:
@RunWith(PowerMockRunner.class)
@PrepareForTest(IConcurrentUtil.class)
@PowerMockIgnore("javax.management.*")
public class ConcurrentUtilTest {
private ConcurrentUser concurrentUser;
@Before
public void setUp() {
concurrentUser = new ConcurrentUser();
}
@Test
public void testThreadSleepCallsSleepCorrect() throws Exception {
PowerMockito.mockStatic(IConcurrentUtil.class);
concurrentUser.callInterfaceMethod();
PowerMockito.verifyStatic(Mockito.times(1));
IConcurrentUtil.threadSleep(3000L);
}
}
But in case you really do want to do some stubbing, here is an example that works with the versions you're using:
PowerMockito.mockStatic(FileUtils.class, Answers.CALLS_REAL_METHODS.get());
PowerMockito.doThrow(new IOException()).when(FileUtils.class, "copyFile", any(File.class), any(File.class));
Here, I am using the 2-args mockStatic signature because I want to do partial stubbing: real methods are called on the FileUtils class unless I stub it, as I do in the second line. You could use the 1-arg version as well if you don't mind all static methods being stubbed with the default answer.
You can also have a look at this answer and this one.