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

标签 java unit-testing mocking powermock

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

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

示例代码:

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:

MockRepository.addAfterMethodRunner(new MockitoStateCleaner());

此可运行程序会清理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);
    }
}

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

@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");
}

关于java - 每次使用 PowerMock 进行测试后,模拟行为都会重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20699091/

相关文章:

python - 模拟范围超出当前测试

unit-testing - 似乎无法起订量 EF CodeFirst 4.1。有帮助吗?

c# - 模拟单元测试 - 获取实现接口(interface)的类的详细信息

java - 如何调用其他EAR的bean方法

java - LMAX干扰者: How to control the speed of producers?

asp.net-mvc - 您如何在 MVC .net 中测试 cookie?

javascript - 如何在单元测试环境中模拟 browserHistory?

java - 如何模块化 A* 中的启发式(运行时启发式)

java - 在 Java 中使用框架和线程

unit-testing - 测试中的整个单轨操作调用