无法模拟 System.currentTimeMillis()

3

我正在使用TestNG编写单元测试。问题是当我模拟System.currentTimeMillis时,它返回实际值而不是模拟值。理想情况下,它应该返回0L,但它返回了实际值。我该怎么做才能继续?

class MyClass{

    public void func1(){
       System.out.println("Inside func1");
       func2();
    }

    private void func2(){
        int maxWaitTime = (int)TimeUnit.MINUTES.toMillis(10);
        long endTime = System.currentTimeMillis() + maxWaitTime; // Mocking not happening
        while(System.currentTimeMillis() <= endTime) {
                System.out.println("Inside func2");
        }
    }
}


@PrepareForTest(System.class)
class MyClassTest extends PowerMockTestCase{
   private MyClass myClass;
   
   @BeforeMethod
   public void setup() {
     MockitoAnnotations.initMocks(this);
     myclass = new MyClass();
   }
   @Test    
   public void func1Test(){
      PowerMockito.mockStatic(System.class)
      PowerMockito.when(System.currentTimeMillis()).thenReturn(0L);
      myclass.func1();
   }
}

https://dev59.com/U3I-5IYBdhLWcg3wI0t9 - OneCricketeer
3个回答

6

创建一个包构造器,可以传入 java.time.Clock

class MyClass{ 
    private Clock clock;
    public MyClass() {
        this.clock = Clock.systemUTC();
    } 
    // for tests 
    MyClass(Clock c) {
        this.clock = c;
   } 

然后为测试模拟它,并使用this.clock.instant()来获取时钟的时间。


0

你需要在类MyClassTest中添加注解@RunWith(PowerMockRunner.class)

不过,我建议重构代码使用java.time.Clock而不是模拟。


你确定在TestNG中应该使用@RunWith(PowerMockRunner.class)吗?因为我遇到了一个错误。 - Dawson Smith

-1

不必使用 PowerMock,你可以使用 Mockito,它也有一个 mockStatic 方法。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>

请参考此答案,其中包含使用LocalDate的示例。

以下是在您的情况下它应该看起来的样子。

try(MockedStatic<System> mock = Mockito.mockStatic(System.class, Mockito.CALLS_REAL_METHODS)) {
    doReturn(0L).when(mock).currentTimeMillis();
    // Put the execution of the test inside of the try, otherwise it won't work
}

请注意使用 Mockito.CALLS_REAL_METHODS,它将保证每当使用另一个方法调用 System 时,它都会执行该类的真实方法。

MockedStatic不可用。Intellij无法导入任何此类类。 - Dawson Smith
在测试中不建议依赖于实际系统时间,特别是在处理时区时。 - OneCricketeer
@OneCricketeer 但我必须这样做。我无法在我的端上更改实际代码。 - Dawson Smith
@DawsonSmith,你应该使用Mockito来完成这个。 - Yassin Hajaj
2
这将是很棒的,但不幸的是 MockedStatic 不允许模拟 System 方法,否则你会得到一个 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 异常。请参见 此 GitHub 问题评论 以了解原因。 - mrts
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接