Mock java.time.format.DateTimeFormatter class

匿名 (未验证) 提交于 2019-12-03 01:58:03

问题:

I'm trying to mock the DateTimeFormatter class. I've done the following:

@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 uses it to format LocalDateTime.now(ZoneId.of("UTC"));. The formatted string is then further used to generate another string. I need to ensure that the string is properly generated. So I need to return a consistent date from either the formatter or mock the LocalDateTime.now(..) static method

What am I doing wrong?

回答1:

An alternative to mocking LocalDateTime.now() is to inject the clock into your class and change your (or add another) constructor like this:

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

Then in your test:

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


回答2:

On the mockito wiki : Don't mock types you don't own !

This is not a hard line, but crossing this line may have repercussions! (it most likely will.)

  1. Imagine code that mocks a third party lib. After a particular upgrade of a third library, the logic might change a bit, but the test suite will execute just fine, because it's mocked. So later on, thinking everything is good to go, the build-wall is green after all, the software is deployed and... Boom
  2. It may be a sign that the current design is not decoupled enough from this third party library.
  3. Also another issue is that the third party lib might be complex and require a lot of mocks to even work properly. That leads to overly specified tests and complex fixtures, which in itself compromises the compact and readable goal. Or to tests which do not cover the code enough, because of the complexity to mock the external system.

Instead, the most common way is to create wrappers around the external lib/system, though one should be aware of the risk of abstraction leakage, where too much low level API, concepts or exceptions, goes beyond the boundary of the wrapper. In order to verify integration with the third party library, write integration tests, and make them as compact and readable as possible as well.

Mock type that you don't have the control can be considered a (mocking) antipattern. While DataTimeFormatter is pretty much standard, one should not consider there won't be any behavior change in upcoming JDK releases (it already happened numerous time in other part of the API, just look at the JDK release notes).

My point is that if the code needs to mock a type I don't own, the design should change asap so I, my colleagues or future maintainers of this code won't fall in these traps.

Also the wiki links to other blogs entries describing issues they had when they tried to mock type they didn't have control.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!