Dateをmockするメモ
0. 時刻が絡むとめんどくさい
使い古された内容だけに、多分に自分用メモ。
よくこんなコードを書かないだろうか。僕はとってもよく書く。
Date date1 = new Date();
// あるいは
Date date2 = Date.from(Instant.now());
よくある「現在時刻が必要な処理」で出てくるやつである。
プロダクションコードだけを考えるなら、まったくこれで問題はないと思うんだけど、ちゃんと時刻が利用できているかどうかをユニットテストで確認しようとすると、これでは途端に問題になる。
こういう場合Date部分を生成部分を固定の値を返すようなモックに置き換えることができれば、安定してテストが成立しうるので、その方法を調べることに。
1. mockしてやる
ググってみると、Overriding System Time for Testing in Javaという、安定のbaeldungさんの記事がヒット。
要はInstant.now()をモックすることで対応可能とのこと。
「そういやspring-boot-starter-testにはmockito含まれてたよな?」と思い出したので確認してみる。
$ ./gradlew dependencies
\--- org.springframework.boot:spring-boot-starter-test -> 2.6.3
+--- org.mockito:mockito-core:4.0.0
+--- org.mockito:mockito-junit-jupiter:4.0.0
| +--- org.mockito:mockito-core:4.0.0 (*)
うむ、間違いなし。PoCプロジェクトにしたSpring Boot 2.6.3では、mockito-core 4.0.0が入っているようだ。
これを利用して、固定の時刻を返すDateを作ってみる。
プロダクションコード
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class TimeNotification {
@JsonProperty("current_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Tokyo")
private Date currentTime;
}
@RestController
public class MainController {
@GetMapping("/")
public TimeNotification notifyTime() {
return new TimeNotification(Date.from(Instant.now()));
}
}
テストコード
@Test
void index() throws Exception {
// Instant側はZ時刻帯(=UTC)、ZoneInfoはJSTなので、9時間ずらす
Clock clock = Clock.fixed(Instant.parse("2022-02-22T12:11:23Z"), ZoneId.of("Asia/Tokyo"));
Instant instant = Instant.now(clock);
try(MockedStatic mockedInstant = Mockito.mockStatic(Instant.class)) {
mockedInstant.when(Instant::now).thenReturn(instant);
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().json("{\"current_time\":\"2022-02-22 21:11:23\"}"))
.andReturn();
}
}
で、テストを実行してみたのだが、
org.mockito.exceptions.base.MockitoException: The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks Mockito's inline mock maker supports static mocks based on the Instrumentation API. You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'. Note that Mockito's inline mock maker is not supported on Android.
...と怒られる。スタックトレースを読むと、スタティックメソッドのモッキングにはmockito-inlineというライブラリが必要な様子。
build.gradleに追加。
dependencies {
testImplementation "org.mockito:mockito-inline:4.0.0"
}
これでようやくテストが通るようになった。
2. 本日のソースコード
全文はこちらをどうぞ。
« IT資産管理システムで白衣を管理する | トップページ | 後付けでMDMを全社導入した話 »
コメント