Junit 如何使用EasyMock、Joda time和PowerMock将当前系统时间覆盖到Java 8 web应用程序中的特定日期?

Junit 如何使用EasyMock、Joda time和PowerMock将当前系统时间覆盖到Java 8 web应用程序中的特定日期?,junit,java-8,junit4,easymock,java-time,Junit,Java 8,Junit4,Easymock,Java Time,我需要在EasyMock下的测试环境中,在Java 8中单独使用Java.time(因此没有Joda time),模拟时间(到特定的日期,这意味着我不能使用anyLong())进行测试 EasyMock不允许您模拟静态方法,如LocalDateTime.now()。PowerMock有,但我不允许使用PowerMock Joda时间库提供了一种简洁而优雅的模拟时间的方法,它使用DateTimeUtils.setCurrentMillisFixed()和DateTimeUtils.setCurre

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

EasyMock不允许您模拟静态方法,如
LocalDateTime.now()
。PowerMock有,但我不允许使用PowerMock

Joda时间库提供了一种简洁而优雅的模拟时间的方法,它使用
DateTimeUtils.setCurrentMillisFixed()
DateTimeUtils.setCurrentMillisSystem()
返回当前时刻

只是我不允许利用乔达的时间

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

有没有一种方法可以在没有Joda Time的情况下正确地执行它
没有PowerMock

这是有办法的。以下是您需要做的:

在测试的课堂上需要做什么 第一步 将新的
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
  }
  // (...)
}
步骤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();
    }
  }
  // (...) 
}
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(..)
    }
  }
在测试课上需要做什么 步骤3 在测试类中,在调用测试方法
doExecute()
之前,创建一个模拟时钟对象并将其注入到测试类的实例中,然后立即重置它,如下所示:

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();
    }
  }
  // (...) 
}
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(..)
    }
  }

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

正确重置为当前日期亲爱的同事们,请随意评论或完成我的回复。很好!只是一些细节:
Clock.system(Clock.systemDefaultZone().getZone())
是多余的,您只需使用
Clock.systemDefaultZone()
——要获得系统默认时区,只需使用
ZoneId.systemDefaultZone()
(与
Clock.systemDefaultZone().getZone()相同)
java.util.TimeZone.getDefault().toZoneId()
)-只要小心。如果在
doExecute
之后不使用
myService
(或者如果只用于不使用
Clock
的东西),就不需要调用
initDefaultClock
。实际上,我更喜欢使
MyService
不可变(无设置器),并创建两个构造函数:一个没有参数将时钟设置为
clock.systemDefaultZone()
,另一个接收时钟-但现在我正在输入设计细节,可能超出了可测试性的范围。