Mockito在尝试模拟java.lang.System时出现了Mockito异常。

huangapple go评论59阅读模式
英文:

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 版本开始允许模拟静态方法,但不允许模拟 ThreadSystem 的静态方法,详见此 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 类的静态方法。

  1. 创建一个接口 ISystem.java
public interface ISystem {

    String getProperty(String name);

    Long getCurrentTimeInMillis();

}
  1. 创建实现 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();
    }

}
  1. 在你的 DeviceTimeProvider.java 类中使用 Isystem.java 接口。
public class DeviceTimeProvider {

   @NonNull private final ISystem mISystem;

   public DeviceTimeProvider(ISystem iSystem){
       mIsystem = iSystem;
   }

   public Long getLocalTime(){
       return mIsystem.getCurrentTimeInMillis()
   }

}
  1. 最后,在你的测试类中模拟 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);
   }

}

输出
Mockito在尝试模拟java.lang.System时出现了Mockito异常。

英文:

To mock the static methods of java.lang.System class with the help of Mockito.

  1. 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

Mockito在尝试模拟java.lang.System时出现了Mockito异常。

huangapple
  • 本文由 发表于 2020年10月3日 16:44:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/64182348.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定