user871611
user871611

Reputation: 3462

Static mock failing on JDK 17

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

Upvotes: 3

Views: 5138

Answers (1)

Lesiak
Lesiak

Reputation: 26064

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);
    }
}

Upvotes: 2

Related Questions