上次我們成功的撰寫好了 isValidDate()
,並且利用 mockk 框架,來製作了一個假 Clock
固定測試時的時間。
不過,這段測試有沒有更簡單的實作方式呢?
有的,下面我們來提提,利用依賴反轉的原則,讓這段程式更加的簡潔
依賴反轉的觀念,首先要從什麼是依賴講起。
以我們的程式來舉例
fun isValidDate(): Boolean {
val clock = Clock.fixed(Instant.now(), ZoneId.of("UTC"))
val now = LocalDateTime.now(clock)
val dueDate = LocalDateTime.parse("2021-12-31T23:59:59")
return dueDate.isAfter(now)
}
要取的現在時間,我們透過了 Clock
物件,讓 LocalDateTime
可以取得現在時間。所以 isValidDate()
要能取得現在時間,是需要透過 Clock
物件的。
如果這個邏輯是固定不變的,那麼這段程式沒什麼大問題。可是一旦這段程式需要調整,比方說我們在測試階段需要切換不同的 Clock
,那就麻煩了。
所以反過來說,我們可以想辦法讓取得時間不是依賴 Clock.fixed(Instant.now(),ZoneId.of("UTC"))
建立的一個 Clock
物件,而是一個外部傳進來,和 Clock
類別有相同方法的物件,我們就可以既確保程式的邏輯正確,又保有足夠的彈性,可以在需求改變時切換取得時間的方式。
我們調整一下 isValidDate()
fun isValidDate(clock: Clock = Clock.fixed(Instant.now(), ZoneId.of("UTC"))): Boolean {
val now = LocalDateTime.now(clock)
val dueDate = LocalDateTime.parse("2021-12-31T23:59:59")
return dueDate.isAfter(now)
}
這邊我們將 clock
移動到參數,並給予一個預設值。在多數的情境下,我們要取得的邏輯都是現在時間,所以 clock
預設為 Clock.fixed(Instant.now(), ZoneId.of("UTC")))
在測試程式碼內,我們的 在2022-01-01時應該回傳false
可以改成
fun `在2022-01-01時應該回傳false`() {
val fixedClock = Clock.fixed(
Instant.parse("2022-01-01T23:59:59Z"),
ZoneId.of("UTC")
)
assertThat(isValidDate(fixedClock), `is`(false))
}
不利用 mock 的方式,就能抽換掉 isValidDate()
裏面的時間,更加直觀了。
同樣的方式也能修改 在2021-12-30時應該回傳true
fun `在2021-12-30時應該回傳true`() {
val fixedClock = Clock.fixed(
Instant.parse("2021-12-30T23:59:59Z"),
ZoneId.of("UTC")
)
assertThat(isValidDate(fixedClock), `is`(true))
}
這樣,我們的測試就成功調整完成了!