如何使用 EasyMock、没有 Joda Time 和 PowerMock 在 Java 8 Web 应用程序中将当前系统时间覆盖为特定日期?

Kir*_*kow 5 junit easymock junit4 java-8 java-time

我需要在 Java 8 中模拟时间(到特定日期,这意味着我可能不会使用anyLong())以java.time在 EasyMock 下的测试环境中单独使用,因此没有 Joda Time。

EasyMock 不允许你模拟像LocalDateTime.now(). PowerMock 可以,但我不允许使用 PowerMock。

Joda Time 库提供了一种简洁优雅的方式来模拟时间DateTimeUtils.setCurrentMillisFixed(),并DateTimeUtils.setCurrentMillisSystem()回到现在的瞬间。

只有我不允许使用 Joda Time。

我被告知使用模拟时钟java.time.Clock类实例并将其注入LocalDateTime.now()如下:LocalDateTime.now(mockClock)

有没有办法在没有 Joda TimePowerMock 的情况下正确实现它?

Kir*_*kow 2

发生这种情况是有办法的。您需要执行以下操作:

测试类中需要做什么

步骤1

java.time.Clock向测试类添加一个新属性MyService,并确保使用实例化块或构造函数以默认值正确初始化新属性:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  private Clock clock;
  public Clock getClock() { return clock; }
  public void setClock(Clock newClock) { clock = newClock; }

  public void initDefaultClock() {
    setClock(
      Clock.system(
        Clock.systemDefaultZone().getZone() 
        // You can just as well use
        // java.util.TimeZone.getDefault().toZoneId() instead
      )
    );
  }
  { 
    initDefaultClock(); // initialisation in an instantiation block, but 
                        // it can be done in a constructor just as well
  }
  // (...)
}
Run Code Online (Sandbox Code Playgroud)

第2步

将新属性注入clock到调用当前日期时间的方法中。例如,在我的例子中,我必须检查数据库中存储的日期是否发生在 之前LocalDateTime.now(),我将其替换为LocalDateTime.now(clock),如下所示:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  protected void doExecute() {
    LocalDateTime dateToBeCompared = someLogic.whichReturns().aDate().fromDB();
    while (dateToBeCompared.isBefore(LocalDateTime.now(clock))) {
      someOtherLogic();
    }
  }
  // (...) 
}
Run Code Online (Sandbox Code Playgroud)

测试类需要做什么

步骤3

在测试类中,创建一个模拟时钟对象,并在调用测试方法之前将其注入到测试类的实例中doExecute(),然后立即将其重置回来,如下所示:

import java.time.Clock;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import org.junit.Test;

public class MyServiceTest {
  // (...)
  private int year = 2017;  // Be this a specific 
  private int month = 2;    // date we need 
  private int day = 3;      // to simulate.

  @Test
  public void doExecuteTest() throws Exception {
    // (...) EasyMock stuff like mock(..), expect(..), replay(..) and whatnot

    MyService myService = new MyService();
    Clock mockClock =
      Clock.fixed(
        LocalDateTime.of(year, month, day, 0, 0).toInstant(OffsetDateTime.now().getOffset()),
        Clock.systemDefaultZone().getZone() // or java.util.TimeZone.getDefault().toZoneId()
      );
    myService.setClock(mockClock); // set it before calling the tested method

    myService.doExecute(); // calling tested method 

    myService.initDefaultClock(); // reset the clock to default right afterwards with our own previously created method

    // (...) remaining EasyMock stuff: verify(..) and assertEquals(..)
    }
  }
Run Code Online (Sandbox Code Playgroud)

在调试模式下检查它,您将看到 2017 年 2 月 3 日的日期已正确注入myService实例并在比较指令中使用,然后已使用 正确重置为当前日期initDefaultClock()