【问题标题】:Mocking behaviour resets after each test with PowerMock每次使用 PowerMock 进行测试后,模拟行为都会重置
【发布时间】:2012-08-14 15:04:14
【问题描述】:

我正在使用 PowerMock 编写单元测试,模拟一些实用程序类的行为。为测试类定义一次行为(通过@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";
  }
}

知道第二次测试失败的原因吗?

【问题讨论】:

    标签: java unit-testing mocking powermock


    【解决方案1】:

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

    MockRepository.addAfterMethodRunner(new MockitoStateCleaner());
    

    这个runnable清除了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");
    }
    

    【讨论】:

    • 感谢您解决这个问题。我知道 Mockito 在每次测试后都会清理模拟对象的内部状态。我只是希望每次测试不要调用一次 setUp() 方法。显然 PowerMockito.mock() 的作用是一样的。
    猜你喜欢
    • 2011-12-09
    • 2022-01-23
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2020-08-24
    • 2020-01-23
    相关资源
    最近更新 更多