Java 8から標準ライブラリとして提供されているClockというクラスを利用して、現在時刻を取得することができます。
現在時刻を取得するためにSystem.currentTimeMills()
やLocalDateTime.now()
などのstatic methodを呼び出して利用する形が多いと思います。
ただ、static methodを利用して現在時刻を取得してしまうと、テストで利用する際に時刻のスタブを用意しづらいという問題があります。
Clockクラスは、static methodではなくインスタンスのメソッドを使って現在時刻を取得するため、テストにおいてスタブを用意しやすいというメリットがあります。
また、スタブとして特定のInstantを返すfixed
というメソッドが用意されているため、スタブの設定も簡単におこなうことができます。
@Test void testFixed() { final Clock c = Clock.fixed(Instant.parse("2021-01-01T00:00:00Z"), ZoneId.systemDefault()); final Instant actual = c.instant(); assertEquals(Instant.parse("2021-01-01T00:00:00Z"), actual); }
例えば、SpringでClockを利用する際には、以下のようにBeanとしてClockインスタンスを定義しておき、
@Bean public Clock clock(){ return Clock.system(ZoneId.of("Asia/Tokyo")); }
プロダクションコードではコンストラクタインジェクションでDIをおこなって利用し、
@Component class SampleBean { private final Clock clock; public void sample(){ // ... Instant instant = clock.instant(); // ... } }
テストコードでは@MockBean
とMockitoを利用して固定のInstantを返す、といった形で使います。
class SampleBeanTest { @MockBean Clock clock; @InjectMocks SampleBean sampleBean; @Test public testSample(){ when(clock.instant()).thenReturn(Instant.parse("2021-01-01T00:00:00Z")) // ... } }
ちなみにいろいろな日付/時間クラスのnow()
メソッドの裏側では、Clockインスタンスのinstant()
メソッドが利用されています。
jdk/LocalDateTime.java at 48d8650ae187821d0e79f7353c2f039518e313b1 · openjdk/jdk · GitHub
jdk/LocalDate.java at 48d8650ae187821d0e79f7353c2f039518e313b1 · openjdk/jdk · GitHub
jdk/Instant.java at 48d8650ae187821d0e79f7353c2f039518e313b1 · openjdk/jdk · GitHub