英文:
MockitoException when trying to mock java.lang.System
问题
以下是翻译好的内容:
我有一个测试案例,用于模拟 java.lang.System
类的静态方法:
@Test
fun `getLocalTime()`() {
// 准备
val staticMock = Mockito.mockStatic(System::class.java)
Mockito.`when`(System.currentTimeMillis()).thenReturn(1000L)
// 执行操作
val res = deviceTimeProvider.getLocalTime()
// 断言
Truth.assertThat(res).isEqualTo(1000L)
staticMock.close()
}
但是当我运行测试时,我得到了这个错误:
org.mockito.exceptions.base.MockitoException: 无法对 java.lang.System 的静态方法进行模拟,以避免干扰类加载,从而导致无限循环。
为什么会发生这种情况?如何模拟 java.lang.System
类的方法呢?
英文:
I have a test case that mock a static method of 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()
}
But when I run the test, I got this error:
> 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
Why does this happen? How can I mock methods of java.lang.System
class?
答案1
得分: 7
自 Mockito 自 3.4.0 版本开始允许模拟静态方法,但不允许模拟 Thread
和 System
的静态方法,详见此 GitHub 评论
最后请注意,Mockito 不允许模拟 System(和 Thread)的静态方法。这些方法与类加载紧密关联,发生在同一线程中。在某些情况下,我们可能会在类加载中添加仪表化以临时禁用其中的静态模拟,以便模拟这些类,此时我们还需要禁用它们的增强属性。但您可以轻松模拟 Instant.now()。
英文:
While Mockito since 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().
答案2
得分: 1
如果您喜欢不太美观的解决方案,您仍然可以使用 PowerMockito
来模拟 System
@PrepareForTest(System.class)
public class TestCase {
@BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(1000L);
}
...
但如果可能的话,我会避免模拟系统类。您仍然可以将其包装在方法中并模拟此方法。
英文:
If you like ugly solutions you can still mock System with PowerMockito
@PrepareForTest(System.class)
public class TestCase {
@BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(1000L);
}
...
But I would avoid mocking System classes if possible. You can still wrap it in method and mock this method.
答案3
得分: 1
以下是翻译好的内容:
用 Mockito 模拟 java.lang.System
类的静态方法。
- 创建一个接口
ISystem.java
public interface ISystem {
String getProperty(String name);
Long getCurrentTimeInMillis();
}
- 创建实现
ISystem
接口的实现类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();
}
}
- 在你的
DeviceTimeProvider.java
类中使用Isystem.java
接口。
public class DeviceTimeProvider {
@NonNull private final ISystem mISystem;
public DeviceTimeProvider(ISystem iSystem){
mIsystem = iSystem;
}
public Long getLocalTime(){
return mIsystem.getCurrentTimeInMillis()
}
}
- 最后,在你的测试类中模拟
ISystem
接口。
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);
}
}
英文:
To mock the static methods of java.lang.System
class with the help of Mockito.
- Create an interface i.e
ISystem.java
public interface ISystem {
String getProperty(String name);
Long getCurrentTimeInMillis();
}
2- Create the implementation class of ISystem interface i.e 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- Use Isystem.java
inside your DeviceTimeProvider.java
class.
public class DeviceTimeProvider {
@NonNull private final ISystem mISystem;
public DeviceTimeProvider(ISystem iSystem){
mIsystem = iSystem;
}
public Long getLocalTime(){
return mIsystem.getCurrentTimeInMillis()
}
}
4- Now finally mock the ISystem interface inside your test 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);
}
}
OUTPUT
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论