时间依赖单元测试

poj*_*ojo 72 java junit

我需要测试一个函数,其结果将取决于当前时间(使用Joda时间isBeforeNow()).

    public boolean isAvailable() {
    return (this.someDate.isBeforeNow());
}
Run Code Online (Sandbox Code Playgroud)

是否可以使用Mockito存根/模拟系统时间,以便我可以可靠地测试功能?

Jon*_*eet 125

使代码可测试的最佳方法(IMO)是将"当前时间是什么"的依赖关系提取到自己的接口中,使用当前系统时间(正常使用)的实现和允许您设置时间的实现,按你想要的那样推进它等.

我在各种情况下都使用过这种方法,而且效果很好.设置起来很简单 - 只需创建一个接口(例如Clock),它有一个方法可以以您想要的任何格式为您提供当前时刻(例如使用Joda Time,或者可能是a Date).

  • @Laurent:我认为这实际上并不那么优雅.从根本上说,我认为"获取当前时间"*这样的服务是*依赖性(就像我将随机数生成视为依赖关系一样)所以我认为明确这样做是件好事.这意味着您也可以并行化测试等. (21认同)
  • Joda时间内置了对该抽象的支持(请参阅我的回答),因此您不必在代码中引入它. (7认同)
  • 采取的点.不要误会我的意思:我通常赞成抽象.但是,在现实生活中,当前时间的概念很难抽象出来,尤其是在使用不抽象这个概念的第三方库时. (5认同)
  • @Laurent:哦,是的,当你使用第三方库时,它很棘手......但是你会遇到setCurrentMillisFixed的同样问题,除非你的第三方库碰巧使用了Joda Time :( (3认同)
  • @Jon:我完全同意你的看法.现在Java 8有抽象类Clock. (3认同)
  • @Rogerio:我认为我们必须同意不同意。我认为使依赖关系明确是一件好事,允许并行化测试,以及对与时间相关的所有内容进行更全面的测试。 (2认同)
  • @Rogerio:事情就是这样:我认为它是*固有的*复杂性,仅仅是明确的.我怀疑如果它总是*作为依赖而不是静态方法提供,你不会建议创建一个静态方法,而你实际上认为这很难看.但正如我已经多次说过的那样,我认为我们必须同意不同意 - 如果你愿意,可以随意回复,但我不打算在这个已经很长的帖子中添加任何评论. (2认同)
  • 从系统中获取当前时间是一个副作用,这意味着执行此操作的任何功能都不再是纯粹的。另一方面,纯函数非常容易测试,因为它们是完全确定的。我能想到的解决此问题的唯一方法是,使副作用尽可能远,这将导致Jon提出解决方案。https://github.com/Frege/frege是JVM的haskell实现,它通过引入_IO_类型很好地涵盖了这一点,该类型声明给定函数可能产生副作用。 (2认同)

Lau*_*eyn 62

Joda时间支持通过类setCurrentMillisFixedsetCurrentMillisOffset方法设置"假"当前时间DateTimeUtils.

请参阅https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html

  • 但这些是静态方法 - 您将通过这种方式在单元测试之间引入依赖关系.因此,我更喜欢Jon Skeets解决方案. (11认同)

xli*_*xli 21

Java 8引入了抽象类java.time.Clock,允许您使用替代实现进行测试.这正是Jon在当时的回答中提出的建议.

  • @Jubobs 如果没有将 `Clock` 作为参数传递给 `now()`,你就无法控制 `LocalDateTime.now()` 返回的当前时间。 (2认同)