Reading the system clock directly within unit tests introduces non-determinism. Tests that rely on the current wall-clock time are "flaky": they may pass today but fail tomorrow, or behave differently depending on the time zone and local time of the CI/CD runner.
To ensure that they are repeatable and predictable, .now() methods like LocalDate.now(),
LocalDateTime.now(), or Instant.now() should only be called with a fixed clock in unit tests. Legacy APIs such as
System.currentTimeMillis(), new Date(), and Calendar.getInstance() have the same problem and should be replaced
with clock injection. Other methods that explicitly call the system clock, such as Clock.system(ZoneId zone),
Clock.systemDefaultZone() and Clock.systemUTC() should also be avoided in tests.
When a test uses the system clock, it relies on an external, uncontrollable state. This makes it impossible to:
The best practice is to inject a java.time.Clock instance into the class or method being tested. In production code,
Clock.systemDefaultZone() can be used, whereas in test code, Clock.fixed(Instant fixedInstant, ZoneId zone) should be
called, or a mock Clock be injected. This ensures that tests remain deterministic regardless of when or where they are run.
The test below is flaky because assumes that the second call to Instant.now() returns an instant that is later than the first, which
might not be true depending on the environment in which the test is run.
@Test
void testTimeDifference() {
Instant instant1 = Instant.now();
Instant instant2 = Instant.now();
assertTrue(instant1.isBefore(instant2)); // Noncompliant
}
In the second example below, the service uses a static call to Instant.now(). This makes it impossible to mock the time without using
advanced (and often discouraged) static mocking techniques.
public class SecurityService {
public boolean isTokenValid(Instant issuedAt) {
return issuedAt.isAfter(Instant.now().minus(1, ChronoUnit.HOURS));
}
}
public class SecurityServiceTest {
@Test
void testTokenValidation() {
SecurityService service = new SecurityService();
assertTrue(service.isTokenValid(Instant.now().minusSeconds(60))); // Noncompliant: the test is non-deterministic and depends on the execution time.
}
}
Here, the first instant is guaranteed to be before the second, because it is fixed, and the second is explicitly set to a later moment.
@Test
void testTimeDifference() {
Instant instant1 = Instant.parse("2026-05-07T10:00:00Z"); // Compliant
Instant instant2 = instant1.plus(1, ChronoUnit.MINUTES);
assertTrue(instant1.isBefore(instant2));
}
In the solution below, the Clock is a field in the class (often injected by a framework like Spring). In the test, we use @Mock to control exactly what time the service "thinks" it is.
public class SecurityService {
private final Clock clock;
public SecurityService(Clock clock) {
this.clock = clock;
}
public boolean isTokenValid(Instant issuedAt) {
return issuedAt.isAfter(Instant.now(clock).minus(1, ChronoUnit.HOURS));
}
}
@ExtendWith(MockitoExtension.class)
public class SecurityServiceTest {
@Mock
private Clock clock;
@Test
void testTokenValidationWithMock() {
Instant fixedPoint = Instant.parse("2026-05-07T10:00:00Z");
// Stub the mock clock to behave like a fixed clock.
when(clock.instant()).thenReturn(fixedPoint);
when(clock.getZone()).thenReturn(ZoneOffset.UTC);
SecurityService service = new SecurityService(clock);
Instant issuedAt = Instant.parse("2026-05-07T09:30:00Z");
assertTrue(service.isTokenValid(issuedAt)); // Compliant: this is now deterministic, as 09:30 is within 1 hour of 10:00.
}
}