I'm writing unit tests using PowerMock, mocking behaviour of some util classes. Defining behaviour once for test class (by @BeforeClass annotation) causes:
Sample code:
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest( {A.class, B.class})
public class TestMockedMethods {
private static B b;
@BeforeClass
public static void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}
@Test
public void test1() { // PASS
Assert.assertEquals("X", A.getVal());
Assert.assertEquals("Y", b.getVal());
}
@Test
public void test2() { // FAIL
Assert.assertEquals("X", A.getVal()); // actual="A"
Assert.assertEquals("Y", b.getVal()); // actual="B"
}
}
class A {
static String getVal() {
return "A";
}
}
class B {
String getVal() {
return "B";
}
}
Any ideas why second test is failing?
PowerMock is an extension of other Mocking frameworks like Mockito or EasyMock that comes with more powerful capabilities.
Both tools are “hiding away” the collaborators in the class under test replacing them with mock objects. The division of work between the two is that Mockito is kind of good for all the standard cases while PowerMock is needed for the harder cases. That includes for example mocking static and private methods.
Normally, you will not need to reset your mocks; instead, you will need to create new mocks for each test method. Instead of using reset(), consider writing short, focused test methods rather than lengthy, over-specified tests.
Try moving your static mock setup to an @BeforeClass setup method, but leave your reset(mocks) call in your test setup() method. You want to setup your mockStatic only once, but because they're static, you will want to reset them for every test or they'll muddle with subsequent tests.
The method PowerMockito.mockStatic(...)
invokes MockCreator.mock(...)
. This method regsiters a Runnable that will be executed after each test :
MockRepository.addAfterMethodRunner(new MockitoStateCleaner());
This runnable cleans the internal state of Mockito :
private static class MockitoStateCleaner implements Runnable {
public void run() {
clearMockProgress();
clearConfiguration();
}
private void clearMockProgress() {
clearThreadLocalIn(ThreadSafeMockingProgress.class);
}
private void clearConfiguration() {
clearThreadLocalIn(GlobalConfiguration.class);
}
private void clearThreadLocalIn(Class<?> cls) {
Whitebox.getInternalState(cls, ThreadLocal.class).set(null);
final Class<?> clazz = ClassLoaderUtil.loadClass(cls, ClassLoader.getSystemClassLoader());
Whitebox.getInternalState(clazz, ThreadLocal.class).set(null);
}
}
So you should execute your setUp before each test.
@Before
public void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With