【问题标题】:Mocking ZonedDateTime Java8模拟 ZonedDateTime Java8
【发布时间】:2020-12-22 09:08:26
【问题描述】:

我有一个生成时间戳的模型构造函数 this.timestamp = null == timestamp ? ZonedDateTime.now().toInstant().toEpochMilli() : timestamp;

如何模拟 ZonedDateTime? 我需要使用测试用例验证时间戳的值是当前时间(以毫秒为单位)。

由于它是一个模型,因此无法在构造函数中注入单独的 clock 类的依赖项,我不希望更改源代码。

【问题讨论】:

  • 1.为什么不直接使用Instant.now() 而不是ZonedDateTime.now().toInstant()?这将避免一个无用的步骤。 2. 不能直接模拟ZonedDateTime.now()(或Instant.now())。如果您想修改或模拟类似的功能,您可以使用 Clock 对象并使用任一类的 now(Clock) 方法而不是无参数的方法。
  • 您的时间戳值是最终值吗?你想创建读取对象并只设置这个单个值还是要模拟整个对象?
  • 在测试时间相关代码时,您可能需要使用依赖注入来使用模拟Clock。您不需要模拟框架。见stackoverflow.com/questions/27067049/…

标签: java junit junit5


【解决方案1】:

这取决于你的班级和你想做什么:

  1. 如果你想模拟一个类的所有属性,并且这个类不是最终的,那么使用像Mockito这样的模拟框架。

    MyClass mocked = Mockito.mock(MyClass.class);       
    Mockito.when(mocked.getTimestamp()).thenReturn(**/ your value **/ )
    
  2. 如果你的类是最终的,你只想模拟这个单一的属性或者属性是最终的:

您可以创建一个静态工厂,为您提供Instant,然后在您的测试中替换工厂。

 class TimeFactory {

  private static Supplier<Instant>  INSTANT_SUPPLIER = Instant::now;
  public static Instant getInstant(){ return INSTANT_SUPPLIER.get(); }
  public static void setInstantSupplier(Supplier<Instant> new){ INSTANT_SUPPLIER= supplier; } 
} 

在你的构造函数中:

this.timestamp = null == timestamp ? TimeFactory.getInstant().toEpochMilli() : timestamp;

现在在您的测试中,您可以使用 setter 方法:

 TimeFactory.setInstantSupplier(()-> /*Your value*/ )
 // create your object

只记得测试后返回默认供应商:

TimeFactory.setInstantSupplier(Instant::now);
  1. 如果你的属性不是最终的,那么添加一个包设置器,它可以在你的测试中使用。

  2. 下一个解决方案(虽然不推荐)是use reflection。但这不是嘲笑,这是使用强制设置私有(事件最终)属性。

  3. 还有一种方法overwrite the clock for tests

【讨论】:

  • 已经有一个Supplier&lt;Instance&gt; 的专用接口,它是Clock(当然它还提供时区信息。但无论如何它们都属于一起)。
  • 很高兴知道,谢谢 :) 但是供应商更多的是一个概念,为了获得一般的想法,如何覆盖供应商。按照他们的说法学习如何钓鱼。
猜你喜欢
  • 1970-01-01
  • 2018-04-03
  • 2016-05-02
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多