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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11955270/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:04:27  来源:igfitidea点击:

Mocking behaviour resets after each test with PowerMock

javaunit-testingmockingpowermock

提问by Kamil Seweryn

I'm writing unit tests using PowerMock, mocking behaviour of some util classes. Defining behaviour once for test class (by @BeforeClass annotation) causes:

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

  • first test invocation to return mocked value
  • second test invocation to return real method return value
  • 第一次测试调用返回模拟值
  • 返回真实方法返回值的第二次测试调用

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?

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

回答by gontard

The method PowerMockito.mockStatic(...)invokes MockCreator.mock(...). This method regsiters a Runnable that will be executed after each test:

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

MockRepository.addAfterMethodRunner(new MockitoStateCleaner());

This runnable cleans the internal state of Mockito:

这个 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);
    }
}

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