令和生まれなのにnew Date()をしているコードは見なかったことにします
結論:LocalDateTime.now(Clock clock)を使う
引数にClock型を渡してあげることで、テスト時に現在時刻を固定化できます。
他の時刻系クラス(Instant・OffsetDateTime・ZonedDateTime)も同様です。
自戒ですが、現在時刻がビジネスロジックに関わる場合は気を付けましょう。
(昔の現場でJunitを全件実行するとテストが失敗する問題を見ました)
サンプルコード
DIで利用する場合は以下のようなイメージ。
@Service
public class AService {
private final Clock clock;
public AService(Clock clock) {
this.clock = clock;
}
public LocalDateTime generateTimestamp() {
return LocalDateTime.now(clock);
}
}
@Configuration
public class ClockConfig {
@Bean
public Clock systemClock() {
return Clock.system(ZoneId.of("Asia/Tokyo"));
}
}
テスト時はConfigurationを上書きできます。
@TestConfiguration
public class TestClockConfig {
@Bean
public Clock fixedClock() {
return Clock.fixed(
Instant.parse("2025-09-01T01:23:45Z"),
ZoneId.of("Asia/Tokyo")
);
}
}
MockBeanを使うとテストケースごと時間を固定できる。
@SpringBootTest
class ReportServiceTest {
@Autowired
ReportService reportService;
@MockBean
Clock clock;
@Test
void morningTest() {
ZoneId zone = ZoneId.of("Asia/Tokyo");
Instant fixedInstant = Instant.parse("2025-08-30T00:00:00Z");
when(clock.instant()).thenReturn(fixedInstant);
when(clock.getZone()).thenReturn(zone);
assertEquals(
LocalDateTime.of(2025, 8, 30, 9, 0),
reportService.generateTimestamp()
);
}
}
間違いがあれば指摘してください!
最後に
Twitterもやってます、エンジニアの友達が出来ればうれしいです!