Java Mock Instant.now()而不将时钟用于构造函数或不使用时钟对象

Java Mock Instant.now()而不将时钟用于构造函数或不使用时钟对象,java,junit,java-8,Java,Junit,Java 8,我的一个方法中有以下代码 ZonedDateTime current = Instant.now().atZone(ZoneId.of(AMERICA_NEW_YORK)); 我想在JUnit测试中模拟current 我尝试了使用java.time.Clock但为此,我需要将其添加到类构造函数中,因为我的代码被写入了旧版本的Spring中,并且使用基于XML的配置。这个类会导致问题,因为如果我使用带有Clock的构造函数,它需要application-context.XML文件中的构造函数参数

我的一个方法中有以下代码

ZonedDateTime current = Instant.now().atZone(ZoneId.of(AMERICA_NEW_YORK));
我想在JUnit测试中模拟
current

我尝试了使用
java.time.Clock
但为此,我需要将其添加到类构造函数中,因为我的代码被写入了旧版本的Spring中,并且使用基于XML的配置。这个类会导致问题,因为如果我使用带有
Clock
的构造函数,它需要application-context.XML文件中的构造函数参数

在上面的代码中,是否有任何方法可以避免构造函数配置和模拟
current

更新

根据帕维尔·斯米尔诺夫的评论,我在下面尝试过,但
current
仍然返回今天的日期,但不是我正在嘲笑的日期

ZonedDateTime exactOneDay = ZonedDateTime.parse("Sun Oct 21 12:30:00 EDT  2018", Parser); 
doReturn(exactOneDay).when(spyEmployeeHelper).getCurrentTime();
employee = getEmployees().get(0);
assertEquals(Integer.valueOf(1), employee.getNoticePeriod());

您可以声明一个返回
ZoneDateTime
的函数:

public ZoneDateTime getCurrentTime () {
    return Instant.now().atZone(ZoneId.of(AMERICA_NEW_YORK));
}
并将该函数的结果分配到
current
字段:

ZonedDateTime current = getCurrentTime();
现在,您只需使用以下方法将其替换为所需值:


使用Mockito时,您可以轻松地进行如下模拟:

    ZoneId zoneId = ZoneId.of("America/New_York");
    ZonedDateTime current = ZonedDateTime.now(zoneId);
    Timestamp timestamp = Timestamp.from(Instant.now());
   
    when(timestamp.toInstant()).thenReturn(Instant.from(current));
添加超时测试示例:

@Test
public void testForTimeout() throws InterruptedException {

    ZoneId zoneId = ZoneId.of("America/New_York");
    ZonedDateTime current = ZonedDateTime.now(zoneId);
    Timestamp timestampBeforeCall = Timestamp.from(Instant.now());

    // Call Class.method() or here instead we just introduce an artificial wait time :
    Thread.sleep(3000);

    Timestamp timestampAfterCall = Timestamp.from(Instant.now());
    long timeoutInMilliseconds = 2000;
    long diff = timestampAfterCall.getTime() - timestampBeforeCall.getTime();
    log.info(String.valueOf(diff));
    if(diff > timeoutInMilliseconds) {
        log.error("Call Timed Out!");
    }
}

您可以尝试使用PowerMockito和mockStatic for Instant.now()的最佳方法是重构您的方法,将这一行提取到一个新方法中。然后,您可以轻松地模拟/监视该方法。最好的方法是更改构造函数并相应地更新
应用程序上下文.xml
。有趣的是,您的标题提到了
mock
,但您的问题中没有提到模拟框架。谢谢Pavel。我也在用同样的方法尝试,但是
当前的
仍然返回今天的日期,而不是我所期望的。请看我更新的问题。@ppb,您提供的代码看起来不错。你能展示你测试的全部代码吗?如何创建spyEmployeeHelper?我正在通过
EmployeeHelper spyEmployeeHelper=mock(EmployeeHelper.class)来创建spyEmployeeHelper这边。我还尝试了
EmployeeHelper spyEmployeeHelper=spy(employeeHelperObject)@Test
public void testForTimeout() throws InterruptedException {

    ZoneId zoneId = ZoneId.of("America/New_York");
    ZonedDateTime current = ZonedDateTime.now(zoneId);
    Timestamp timestampBeforeCall = Timestamp.from(Instant.now());

    // Call Class.method() or here instead we just introduce an artificial wait time :
    Thread.sleep(3000);

    Timestamp timestampAfterCall = Timestamp.from(Instant.now());
    long timeoutInMilliseconds = 2000;
    long diff = timestampAfterCall.getTime() - timestampBeforeCall.getTime();
    log.info(String.valueOf(diff));
    if(diff > timeoutInMilliseconds) {
        log.error("Call Timed Out!");
    }
}