模拟 Instant.now() 而不使用 Clock 进入构造函数或不使用 Clock 对象

ppb*_*ppb 14 java junit java-8

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

ZonedDateTime current = Instant.now().atZone(ZoneId.of(AMERICA_NEW_YORK));
Run Code Online (Sandbox Code Playgroud)

我想current在 JUnit 测试中进行模拟。

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

有没有办法避免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());
Run Code Online (Sandbox Code Playgroud)

eze*_*zer 12

基于 Mockito 的解决方案,其中代码使用普通Instant.now()

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;

import java.time.Clock;
import java.time.Instant;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

public class MockInstantTest {

  private MockedStatic<Clock> clockMock;

  @BeforeEach
  public void setup() {
    mockInstant(1640000000); // set desired return value 2021-12-20T11:33:20Z
  }

  @AfterEach
  public void destroy() {
    clockMock.close();
  }

  private void mockInstant(long expected) {
    Clock spyClock = spy(Clock.class);
    clockMock = mockStatic(Clock.class);
    clockMock.when(Clock::systemUTC).thenReturn(spyClock);
    when(spyClock.instant()).thenReturn(Instant.ofEpochSecond(expected));
  }

  @Test
  void testWithMockedIstant() {
    // invoking Instant.now() will always return the same value
    assertThat(Instant.now().toString()).isEqualTo("2021-12-20T11:33:20Z");
  }
}
Run Code Online (Sandbox Code Playgroud)

解决方案解释

Instant.now()解决方案依赖于调用的事实Clock.systemUTC().instant()

  • Clock是抽象的,所以我们监视非静态方法
  • clock.instant()被嘲笑返回所需的值
  • Clock.systemUTC()是静态的所以我们需要mockStatic
  • 需要使用@Before/来关闭 MockedStatic (或者您可以使用)@Aftertry(MockedStatic<Clock> clockMock = mockStatic(Clock.class)) {...}

  • 不再适用于 JDK 17 (Eclipse Temurin 17.0.2.8)。不过可以使用 JDK 11。 (6认同)
  • `Instant.now()` 返回 `null`;因此,user871611 正确地表明这可能不再适用于 Java 17。 (3认同)

Pav*_*nov 5

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

public ZoneDateTime getCurrentTime () {
    return Instant.now().atZone(ZoneId.of(AMERICA_NEW_YORK));
}
Run Code Online (Sandbox Code Playgroud)

并将该函数的结果分配给该current字段:

ZonedDateTime current = getCurrentTime();
Run Code Online (Sandbox Code Playgroud)

现在您可以使用Mockito 框架将其替换为所需的值:

doReturn(yourValue).when(yourObject).getCurrentTime();
Run Code Online (Sandbox Code Playgroud)