Joda Time には、時間をモック するための便利なDateTimeUtils.setCurrentMillisFixed()があります。
テストでは非常に実用的です。
Java 8 の java.time APIに相当するものはありますか?
Joda Time には、時間をモック するための便利なDateTimeUtils.setCurrentMillisFixed()があります。
テストでは非常に実用的です。
Java 8 の java.time APIに相当するものはありますか?
最も近いものはClock
オブジェクトです。任意の時間を使用して (またはシステムの現在の時間から) Clock オブジェクトを作成できます。すべての date.time オブジェクトnow
には、現在の時刻の代わりに時計オブジェクトを受け取るメソッドがオーバーロードされています。したがって、依存性注入を使用して、Clock に特定の時刻を注入できます。
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
詳細については、 Clock JavaDocを参照してください。
新しいクラスを使用して、Clock.fixed
作成を非表示にし、テストを簡素化しました。
public class TimeMachine {
private static Clock clock = Clock.systemDefaultZone();
private static ZoneId zoneId = ZoneId.systemDefault();
public static LocalDateTime now() {
return LocalDateTime.now(getClock());
}
public static void useFixedClockAt(LocalDateTime date){
clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);
}
public static void useSystemDefaultZoneClock(){
clock = Clock.systemDefaultZone();
}
private static Clock getClock() {
return clock ;
}
}
public class MyClass {
public void doSomethingWithTime() {
LocalDateTime now = TimeMachine.now();
...
}
}
@Test
public void test() {
LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2);
MyClass myClass = new MyClass();
TimeMachine.useFixedClockAt(twoWeeksAgo);
myClass.doSomethingWithTime();
TimeMachine.useSystemDefaultZoneClock();
myClass.doSomethingWithTime();
...
}
私はClock
あなたの生産コードを乱雑に使用していることに気づきました。
JMockitまたはPowerMockを使用して、テスト コードで静的メソッド呼び出しをモックできます。JMockit の例:
@Test
public void testSth() {
LocalDate today = LocalDate.of(2000, 6, 1);
new Expectations(LocalDate.class) {{
LocalDate.now(); result = today;
}};
Assert.assertEquals(LocalDate.now(), today);
}
編集:ここで同様の質問に対するJon Skeetの回答に関するコメントを読んだ後、私は過去の自分に同意しません。何よりも、この議論は、静的メソッドをモックするときにテストを並列化できないことを確信させました。
ただし、レガシーコードを処理する必要がある場合は、静的モックを使用できます/使用する必要があります。
少し遅れましたがjava.date
、Kotlin で API を使用して時間をモックするために使用するのは次のとおりです。
val now = LocalDate.of(2021, Month.FEBRUARY, 19)
val clock = Clock.fixed(Instant.ofEpochSecond(
now.atStartOfDay().toEpochSecond(ZoneOffset.UTC)
), ZoneId.systemDefault())
次に、クロックをクラスに渡してテストできます
val classToTest = MyClass(clock)
もちろん、テスト可能なクラス内では、時計を使用して日付または時刻を取得します。
class MyClass(private val clock: Clock = Clock.systemDefaultZone()) {
// ...
fun doSomething() = LocalDate.now(clock)...
私java.time.Clock
はmockito依存関係で使用しました
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-inline")
サービス クラスはClock
、テストでモックされるフィールドを使用します。
@Service
public class DeliveryWithDateService {
private final Clock clock = Clock.systemUTC();
public Delivery plan(UUID orderId) {
return Delivery.builder()
.id(UUID.randomUUID())
.orderId(orderId)
.createdAt(ZonedDateTime.now(clock))
.plannedAt(ZonedDateTime.now(clock)
.plusDays(1)
.withHour(8)
.truncatedTo(ChronoUnit.HOURS))
.build();
}
public Delivery ship(Delivery delivery) {
return Delivery.builder()
.id(delivery.getId())
.orderId(delivery.getOrderId())
.createdAt(delivery.getCreatedAt())
.shippedAt(ZonedDateTime.now(clock))
.build();
}
}
@Value
@Builder
public class Delivery {
private UUID id;
private UUID orderId;
private ZonedDateTime createdAt;
private ZonedDateTime plannedAt;
private ZonedDateTime shippedAt;
}
単体テストでは、 を使用してMockito.mockStatic
をモックしClock
ます。
@SpringBootTest
public class DeliveryWithDateServiceTest {
@Autowired
private DeliveryWithDateService deliveryService;
private static Clock clock;
private static ZonedDateTime now;
@BeforeAll
static void setupClock() {
clock = Clock.fixed(
Instant.parse("2020-12-01T10:05:23.653Z"),
ZoneId.of("Europe/Prague"));
now = ZonedDateTime.now(clock);
var clockMock = Mockito.mockStatic(Clock.class);
clockMock.when(Clock::systemUTC).thenReturn(clock);
}
@Test
void delivery_is_planned() {
var orderId = UUID.randomUUID();
var delivery = deliveryService.plan(orderId);
var tomorrowAt8am = now.plusDays(1).withHour(8).truncatedTo(ChronoUnit.HOURS);
assertAll(
() -> assertThat(delivery).isNotNull(),
() -> assertThat(delivery.getId()).isNotNull(),
() -> assertThat(delivery.getOrderId()).isEqualTo(orderId),
() -> assertThat(delivery.getCreatedAt()).isEqualTo(now),
() -> assertThat(delivery.getPlannedAt()).isEqualTo(tomorrowAt8am),
() -> assertThat(delivery.getShippedAt()).isNull()
);
}
@Test
void delivery_is_shipped() {
var delivery = deliveryService.plan(UUID.randomUUID());
var shipped = deliveryService.ship(delivery);
assertAll(
() -> assertThat(shipped).isNotNull(),
() -> assertThat(shipped.getId()).isEqualTo(delivery.getId()),
() -> assertThat(shipped.getOrderId()).isEqualTo(delivery.getOrderId()),
() -> assertThat(shipped.getCreatedAt()).isEqualTo(delivery.getCreatedAt()),
() -> assertThat(shipped.getShippedAt()).isEqualTo(now)
);
}
}
jmockit を使用します。
コード:
// Mocking time as 9am
final String mockTime = "09:00:00"
new MockUp<LocalTime>() {
@Mock
public LocalTime now() {
return LocalTime.parse(mockTime);
}
};
輸入品:
import mockit.MockUp;
import mockit.Mock;
依存:
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.41</version>