⏰
Javaでテストで日時を差し替える
LocalDate.now()などを利用するときは以下のようなクラスを経由し
package org.SystemDate;
import java.time.*;
public class SystemDate {
static Clock clock = Clock.systemDefaultZone();
public static YearMonth currentMonth() {
return YearMonth.now();
}
public static LocalDate today() {
return LocalDate.now(clock);
}
public static LocalDateTime now() {
return LocalDateTime.now(clock);
}
public static LocalTime time() {
return LocalTime.now(clock);
}
}
テストでは以下のように利用する
package org.SystemDate;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
public class SystemDateTest {
@BeforeEach
void setUp() {
// LocalDate.now()で返ってくる値を指定する
TestDateUtil.setup(LocalDate.of(2023, 11, 10));
}
@Test
void テスト日付を固定できる() {
LocalDate today = SystemDate.today();
Assertions.assertEquals(LocalDate.of(2023, 11, 10), today);
}
}
package org.SystemDate;
import java.lang.reflect.Field;
import java.time.*;
public class TestDateUtil {
public static void setup(LocalDate localDate) {
setup(LocalDateTime.of(localDate, LocalTime.now()));
}
public static void setup(LocalDate localDate, LocalTime localTime) {
setup(LocalDateTime.of(localDate, localTime));
}
public static void setup(LocalDateTime localDateTime) {
try {
Class<?> clazz = SystemDate.class;
//SystemDateクラスのフィールド(メンバー変数)であるclockのFieldを取得
Field clock = clazz.getDeclaredField("clock");
// clockフィールドに対してアクセス制限を外す
clock.setAccessible(true);
// clockフィールドに対して、第二引数を設定する。第一引数はstaticの場合利用しないのでnull。
clock.set(null, Clock.fixed(localDateTime.toInstant(ZoneOffset.ofHours(9)), ZoneId.systemDefault()));
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
public static void clear() {
try {
Class<?> clazz = SystemDate.class;
Field clock = clazz.getDeclaredField("clock");
clock.setAccessible(true);
clock.set(null, Clock.systemDefaultZone());
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
これでテストコード側が好きな日時にできる。
Discussion