The same code worked perfectly with JDK 11. Switching to JDK 17 makes the test fail, since Instant.now()
returns null
.
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@Test
void mockStatic() {
final Instant instantExpected = Instant.parse("2022-03-10T10:15:30Z");
final Clock spyClock = spy(Clock.class);
when(spyClock.instant()).thenReturn(instantExpected);
try (final MockedStatic<Clock> clockMock = mockStatic(Clock.class)) {
clockMock.when(Clock::systemUTC).thenReturn(spyClock);
final Instant now = Instant.now();
assertEquals(instantExpected, now);
}
}
Running on Windows 10, Mockito 4.6.1, Eclipse Temurin 17.0.2.8
The difference stems from the fact that JDK 17 no longer calls Clock.systemUTC()
in implementation of Instant.now()
Please compare:
JDK 17:
public static Instant now() {
return Clock.currentInstant();
}
JDK 15:
public static Instant now() {
return Clock.systemUTC().instant();
}
If you insist on mocking static methods, you could stub Instant.now()
, not Clock.systemUTC()
- thus you don't rely on the implementation of Instant.now()
As discussed in the comments in under your post, this is not the recommended approach - class Clock
was designed specifically to make time-handling code easier to test, use a Clock
in your code instead of calling Instant.now()
@Test
void mockStaticClock() {
final Instant instantExpected = Instant.parse("2022-03-10T10:15:30Z");
try (final MockedStatic<Instant> instantMock = mockStatic(Instant.class)) {
instantMock.when(Instant::now).thenReturn(instantExpected);
final Instant now = Instant.now();
assertEquals(instantExpected, now);
}
}