尝试模拟时出现 MockitoException java.lang.System
MockitoException when trying to mock java.lang.System
我有一个模拟 java.lang.System
class:
静态方法的测试用例
@Test
fun `getLocalTime()`() {
// Arrange
val staticMock = Mockito.mockStatic(System::class.java)
Mockito.`when`(System.currentTimeMillis()).thenReturn(1000L)
// Action
val res = deviceTimeProvider.getLocalTime()
// Assert
Truth.assertThat(res).isEqualTo(1000L)
staticMock.close()
}
但是当我运行测试时,我得到了这个错误:
org.mockito.exceptions.base.MockitoException: It is not possible to
mock static methods of java.lang.System to avoid interfering with
class loading what leads to infinite loops
为什么会这样?我如何模拟 java.lang.System
class 的方法?
虽然 Mockito 自 3.4.0 version allows mocking static methods it is not allowed to mock the Thread
and System
static methods, see this comment on github
Finally note that Mockito forbids mocking the static methods of System (and Thread). Those methods are to much cemented into class loading which happens in the same thread. At some point, we might add instrumentation to class loading to temporarily disable the static mocks within it to make mocking these classes, too, where we also would need to disable their intensification properties. You can however easily mock Instant.now().
如果您喜欢丑陋的解决方案,您仍然可以使用 PowerMockito
模拟系统
@PrepareForTest(System.class)
public class TestCase {
@BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(1000L);
}
...
但我会尽可能避免模拟系统 类。您仍然可以将其包装在方法中并模拟此方法。
在 Mockito 的帮助下模拟 java.lang.System
class 的静态方法。
- 创建一个界面即
ISystem.java
public interface ISystem {
String getProperty(String name);
Long getCurrentTimeInMillis();
}
2- 创建 ISystem 接口的实现 class 即 ISystemImpl.java
public class ISystemImpl implements ISystem {
@Override
public String getProperty(final String name) {
return System.getProperty(name);
}
@Override
public Long getCurrentTimeInMillis() {
return System.currentTimeMillis();
}
}
3- 在 DeviceTimeProvider.java
class.
中使用 Isystem.java
public class DeviceTimeProvider {
@NonNull private final ISystem mISystem;
public DeviceTimeProvider(ISystem iSystem){
mIsystem = iSystem;
}
public Long getLocalTime(){
return mIsystem.getCurrentTimeInMillis()
}
}
4- 现在终于在测试中模拟 ISystem 接口 class。
public class DeviceTimeProviderTest {
private ISystem mISystem;
private DeviceTimeProvider sut;
@Before
public setup(){
mIsystem = mockito.mock(ISystem.class)
sut = new DeviceTimeProvider(mISystem);
}
@Test
public void getDeviceLocalTime(){
Long expectedTime = 1000L;
mockit.when(mISystem.getCurrentTimeInMillis()).thenReturn(expectedTime);
Long actualTime = sut.getLocalTime();
Assert.assertEquals(actualTime, expectedTime);
}
}
输出
我有一个模拟 java.lang.System
class:
@Test
fun `getLocalTime()`() {
// Arrange
val staticMock = Mockito.mockStatic(System::class.java)
Mockito.`when`(System.currentTimeMillis()).thenReturn(1000L)
// Action
val res = deviceTimeProvider.getLocalTime()
// Assert
Truth.assertThat(res).isEqualTo(1000L)
staticMock.close()
}
但是当我运行测试时,我得到了这个错误:
org.mockito.exceptions.base.MockitoException: It is not possible to mock static methods of java.lang.System to avoid interfering with class loading what leads to infinite loops
为什么会这样?我如何模拟 java.lang.System
class 的方法?
虽然 Mockito 自 3.4.0 version allows mocking static methods it is not allowed to mock the Thread
and System
static methods, see this comment on github
Finally note that Mockito forbids mocking the static methods of System (and Thread). Those methods are to much cemented into class loading which happens in the same thread. At some point, we might add instrumentation to class loading to temporarily disable the static mocks within it to make mocking these classes, too, where we also would need to disable their intensification properties. You can however easily mock Instant.now().
如果您喜欢丑陋的解决方案,您仍然可以使用 PowerMockito
@PrepareForTest(System.class)
public class TestCase {
@BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(1000L);
}
...
但我会尽可能避免模拟系统 类。您仍然可以将其包装在方法中并模拟此方法。
在 Mockito 的帮助下模拟 java.lang.System
class 的静态方法。
- 创建一个界面即
ISystem.java
public interface ISystem {
String getProperty(String name);
Long getCurrentTimeInMillis();
}
2- 创建 ISystem 接口的实现 class 即 ISystemImpl.java
public class ISystemImpl implements ISystem {
@Override
public String getProperty(final String name) {
return System.getProperty(name);
}
@Override
public Long getCurrentTimeInMillis() {
return System.currentTimeMillis();
}
}
3- 在 DeviceTimeProvider.java
class.
Isystem.java
public class DeviceTimeProvider {
@NonNull private final ISystem mISystem;
public DeviceTimeProvider(ISystem iSystem){
mIsystem = iSystem;
}
public Long getLocalTime(){
return mIsystem.getCurrentTimeInMillis()
}
}
4- 现在终于在测试中模拟 ISystem 接口 class。
public class DeviceTimeProviderTest {
private ISystem mISystem;
private DeviceTimeProvider sut;
@Before
public setup(){
mIsystem = mockito.mock(ISystem.class)
sut = new DeviceTimeProvider(mISystem);
}
@Test
public void getDeviceLocalTime(){
Long expectedTime = 1000L;
mockit.when(mISystem.getCurrentTimeInMillis()).thenReturn(expectedTime);
Long actualTime = sut.getLocalTime();
Assert.assertEquals(actualTime, expectedTime);
}
}
输出