I'm attempting to Mock the static method Instant.now() and I continue to keep coming across weird behavior when trying to mock classes from java.time package. Please see my code below on attempting to mock Instant.now()
@RunWith(PowerMockRunner.class)
@PrepareForTest(Instant.class)
public class UnitTestClasss {
@Test
public void unitTestMethod() throws Exception {
mockCurrentTimeAtMidNight();
instanceOfSystemUnderTest.someMethodDependingOnTime();
assertHandledHere();
}
/*See First Error Below */
private void mockCurrentTimeAtMidNight() {
ZonedDateTime current = ZonedDateTime.now();
ZonedDateTime mockMidNight = ZonedDateTime.of(current.getYear(), current.getMonthValue(),
current.getDayOfMonth(), 0, 0, 0, 0,current.getZone());
PowerMockito.mockStatic(Instant.class);
PowerMockito.when(Instant.now()).thenReturn(Instant.from(mockMidNight));
}
/*See Second Error Below */
private void mockCurrentTimeAtMidNight2() {
Calendar cal = Calendar.getInstance();
ZonedDateTime mockMidNight = ZonedDateTime.of(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0, 0,ZoneId.of("US/Eastern"));
Instant instant = mockMidNight.toInstant();
PowerMockito.mockStatic(Instant.class);
PowerMockito.when(Instant.now()).thenReturn(instant);
}
}
Errors 1 org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:495)
E.g. thenReturn() may be missing. Examples of correct stubbing: when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(exception); doThrow(exception).when(mock).someVoidMethod(); Hints: 1. missing thenReturn() 2. you are trying to stub a final method, you naughty developer! 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completedErrors 2: with Reason: [source error]
toInstant()not found injava.time.ZonedDateTime
From what I was able to tell i was getting the error because originally I was calling .now() in my unit test then trying to mock it afterwards. The reason for this is because I thought i could have my test use the method unmocked then mock it so my SUT could then used the mocked form.
I ended up changing this a bit and mocked ZonedDateTime.ofInstant(obj,obj) instead. this is what I did
@Test
public void renamingToArbitraryMethodName() throws Exception {
ZonedDateTime current = ZonedDateTime.now();
ZonedDateTime mockMidNight = ZonedDateTime.of(current.getYear(), current.getMonthValue(),
current.getDayOfMonth(), 0, 0, 0, 0, ZoneId.of("US/Eastern"));
PowerMockito.mockStatic(ZonedDateTime.class);
PowerMockito.when(ZonedDateTime.ofInstant(anyObject(), anyObject())).thenReturn(mockTime);
}
In my scenario this worked for me because I was able to get away with my Test class using .now() while my source for SUT used .ofInstant(...).
You're trying to mock a java.time class, which means you're trying to mock a system class. This requires you to put your own system under test in the @PrepareForTest annotation, because PowerMock can't intercept the loading of the class you're calling, so it has to intercept the loading of your class instead and do its bytecode-rewriting there.
(This doesn't exactly match up with your error message, but would still be a very clear reason why you're having trouble here that you wouldn't have with non-system classes in Mockito and PowerMock both.)
The perils of mocking system classes—on top of the fact that you're mocking data objects, and particularly objects that have explicit unit test features (like the Clock override Andy Turner mentioned in the comments)—are an excellent reason not to use mocks here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With