关于java:每次使用PowerMock进行测试后,模拟行为都会重置

Mocking behaviour resets after each test with PowerMock

我正在使用PowerMock编写单元测试,模拟某些util类的行为。 为测试类定义一次行为(通过@BeforeClass批注)会导致:

  • 第一次测试调用以返回模拟值
  • 第二次测试返回真实方法的返回值

样例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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";
  }
}

任何想法为什么第二次测试失败了?


方法PowerMockito.mockStatic(...)调用MockCreator.mock(...)。 此方法注册一个Runnable,它将在每次测试后执行:

1
MockRepository.addAfterMethodRunner(new MockitoStateCleaner());

这个可运行的清理Mockito的内部状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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);
    }
}

因此,您应该在每次测试之前执行setUp。

1
2
3
4
5
6
7
8
@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");
}