模拟java.time.format.DateTimeFormatter类

我正在尝试模拟DateTimeFormatter类。 我做了以下事情:

@RunWith(PowerMockRunner.class) @PrepareForTest({DateTimeFormatter.class}) public class UnitTest { private DateTimeFormatter mockDateFormatter; private AwesomeClass awesomeClass; @Before public void setUp() { mockDateFormatter = PowerMockito.mock(DateTimeFormatter.class); awesomeClass = new AwesomeClass(mockDateFormatter); } @Test public void shouldToTestSomethingAwesome() { // Other test code PowerMockito.when(mockDateFormatter.format(any(LocalDate.class))) .thenReturn("20150224"); // Other test code } 

AwesomeClass使用它来格式化LocalDateTime.now(ZoneId.of("UTC")); 。 然后,格式化的字符串进一步用于生成另一个字符串。 我需要确保正确生成字符串。 所以我需要从格式化程序返回一致日期或模拟LocalDateTime.now(..)静态方法

我究竟做错了什么?

模拟LocalDateTime.now()的另一种方法是将时钟注入您的类并更改您的(或添加另一个)构造函数,如下所示:

 AwesomeClass(DateTimeFormatter fmt, Clock clock) { //instead of LocalDateTime now = LocalDateTime.now(): LocalDateTime now = LocalDateTime.now(clock); } 

然后在你的测试中:

 new AwesomeClass(formatter, Clock.fixed(the time you want here)); 

在mockito wiki上: 不要嘲笑你不拥有的类型!

这不是一个强硬路线,但越过这条线可能会产生反响! (很可能会。)

  1. 想象一下嘲笑第三方lib的代码。 在第三个库的特定升级之后,逻辑可能会改变一点,但测试套件将执行得很好,因为它被嘲笑。 所以后来,认为一切都很好,毕竟构建墙是绿色的,软件部署和…… 轰隆隆
  2. 这可能表明当前设计与第三方库没有足够的分离。
  3. 另一个问题是第三方库可能很复杂,需要大量的模拟才能正常工作。 这导致过度指定的测试和复杂的固定装置,这本身就损害了紧凑和可读的目标。 或者由于模拟外部系统的复杂性而导致的测试不足以覆盖代码。

相反,最常见的方法是围绕外部lib /系统创建包装器,尽管应该意识到抽象泄漏的风险,其中过多的低级API,概念或exception超出了包装器的边界。 为了validation与第三方库的集成,编写集成测试,并使它们尽可能紧凑和可读。

你没有控件的模拟类型可以被认为是(模拟)反模式。 虽然DataTimeFormatter非常标准 ,但不应该考虑在即将发布的JDK版本中不会有任何行为更改(它已经在API的其他部分发生了很多次,只需查看JDK发行说明)。

我的观点是,如果代码需要模拟我不拥有的类型,那么设计应该尽快改变,因此我,我的同事或此代码的未来维护者不会陷入这些陷阱。

此外,wiki还链接到其他博客条目,这些条目描述了当他们尝试模拟他们无法控制的类型时所遇到的问题。