我正在尝试模拟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(..)静态方法
我做错了什么?
答案 0 :(得分:8)
在mockito wiki上:Don't mock types you don't own !
这不是一个强硬路线,但越过这条线可能会产生影响! (很有可能。)
- 想象一下嘲笑第三方lib的代码。在第三个库的特定升级之后,逻辑可能会改变一点,但测试套件将执行得很好,因为它被嘲笑。所以稍后,认为一切都很好,毕竟构建墙是绿色的,软件已经部署并且...... Boom
- 这可能表示当前设计与第三方库没有足够的分离。
- 另一个问题是第三方lib可能很复杂,需要很多模拟才能正常工作。这会导致过度指定的测试和复杂的固定装置,这本身就会损害紧凑和可读目标。或者由于模拟外部系统的复杂性而导致的测试不足以覆盖代码。
醇>相反,最常见的方法是围绕外部lib /系统创建包装器,尽管应该意识到抽象泄漏的风险,其中过多的低级API,概念或异常超出了包装器的边界。为了验证与第三方库的集成,编写集成测试,并使它们尽可能紧凑和可读。
您没有控件的模拟类型可以被视为(模拟)反模式。虽然DataTimeFormatter
几乎是标准,但是不应该考虑在即将发布的JDK版本中不会有任何行为更改(它已经在API的其他部分发生了很多次,只是看看JDK发行说明)。
我的观点是,如果代码需要模拟我不拥有的类型,那么设计应该更改 asap ,因此我,我的同事或此代码的未来维护者不会涉及这些陷阱。
此外,wiki链接到其他博客条目,这些条目描述了当他们尝试模拟他们无法控制的类型时所遇到的问题。
答案 1 :(得分:4)
模拟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));