用Java控制时间

时间是一件棘手的事情,它总是在变化。 例如,当进行测试时,将这样的移动部分放入代码库中可能会很烦人。 在本文中,我们将看到如何在Java中控制时间。

让我们以一个简单的披萨外送服务示例为例。 它的政策是比萨饼应在10分钟内送达。 当客户要求交货时,系统会根据此策略自动计算交货时间。

public class DeliveryPolicy {
  public Delivery createDelivery(Pizza pizza) {
    LocalDateTime deliveryTime = LocalDateTime.now().plus(10, ChronoUnit.MINUTES);

    return new Delivery(pizza, deliveryTime);
  }
}

How Do we Test it?

由于时间总是在变化,因此我们无法在不更改其代码的情况下非常精确地测试此方法。 我们可以测试一下交货时间近似地在将来的10分钟内,但像所有模糊测试一样,它可能会不时失败,具体取决于执行它的上下文。

Make Dependency Visible

该代码之所以难以测试的原因是它具有隐藏的依赖性:时钟。 自Java 8起,现在Date API的方法以时钟为参数。 然后,我们可以使此依赖性可见。

public class DeliveryPolicy {

  private final Clock clock;

  public DeliveryPolicy() {
    this.clock = Clock.systemDefaultZone();
  }

  public Delivery createDelivery(Pizza pizza) {
    LocalDateTime deliveryTime = LocalDateTime.now(clock).plus(10, ChronoUnit.MINUTES);

    return new Delivery(pizza, deliveryTime);
  }
}

Dependency Injection to the Rescue

现在已经有了依赖项,我们可以像其他任何依赖项一样将其注入到构造函数中,并且测试此方法变得很简单。

public class DeliveryPolicy {

  private final Clock clock;

  public DeliveryPolicy(ClockProvider clockProvider) {
    this.clock = clockProvider.get();
  }

  public Delivery createDelivery(Pizza pizza) {
    LocalDateTime deliveryTime = LocalDateTime.now(clock).plus(10, ChronoUnit.MINUTES);

    return new Delivery(pizza, deliveryTime);
  }
}
public class DeliveryPolicyTest {

  @Test
  public void should_schedule_delivery_ten_minutes_later() {
    ZonedDateTime now = ZonedDateTime.of(LocalDateTime.of(2017, 7, 18, 0, 0, 0), ZoneId.of("+01"));
    DeliveryPolicy policy = new DeliveryPolicy(() -> Clock.fixed(now.toInstant(), now.getZone()));

    Delivery delivery = policy.createDelivery(new Pizza());

    LocalDateTime tenMinutesLater = LocalDateTime.of(2017, 7, 18, 0, 10, 0);
    assertThat(delivery.getDeliveryTime()).isEqualTo(tenMinutesLater);
  }
}

Usage with Spring Framework and Spring Boot

如果您在应用程序中使用Spring Framework,则可以创建一个ClockProvider会提供默认Clock的bean。 此外,如果您使用Spring Boot,它可以让您在集成测试中使用@MockBean注解。

@RunWith(SpringRunner.class)
@SpringBootTest
public class DeliveryPolicyIT {

  @MockBean
  private ClockProvider clockProvider;

  @Autowired
  private DeliveryPolicy policy;

  @Test
  public void should_schedule_delivery_ten_minutes_later() {
    ZonedDateTime now = ZonedDateTime.of(LocalDateTime.of(2017, 7, 18, 0, 0, 0), ZoneId.of("+01"));
    Mockito.when(clockProvider.get()).thenReturn(Clock.fixed(now.toInstant(), now.getZone()));

    Delivery delivery = policy.createDelivery(new Pizza());

    LocalDateTime tenMinutesLater = LocalDateTime.of(2017, 7, 18, 0, 10, 0);
    assertThat(delivery.getDeliveryTime()).isEqualTo(tenMinutesLater);
  }
}
@Configuration
public class ClockConfig {

  @Bean
  public ClockProvider clockProvider() {
    return () -> Clock.systemDefaultZone();
  }
}

Conclusion

我曾经认为时间像随机一样,是很难考验的。 使用Java 8 Date API,它变得微不足道。 您只需要确认时钟上的依赖关系,并将其像其他依赖关系一样对待即可。 现在,我几乎不使用Date API的方法而不传递时钟作为参数。 这使我可以非常轻松地控制整个应用程序中的时间(在单元测试,集成测试或功能测试中)。

from: https://dev.to//rnowif/controlling-the-time-in-java-43kh

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值