[Day 25] 如果我们不想 mock Clock 怎麽办呢?谈依赖反转

上次我们成功的撰写好了 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))  
}

这样,我们的测试就成功调整完成了!


<<:  Day 28-制作购物车之Redux 3

>>:  从 IT 技术面细说 Search Console 的 27 组数字 KPI:终与始

Progressive Web App Service Worker (4)

什麽是 Service Workers Service Workers 的角色是位於 Web App...

[DAY 18]让BOT 24小时在线(GCP版本)

前几天有写一篇用replit让bot24小时在线的文章 但测试几天後发现bot执行的速度明显变慢个2...

Day11. UX/UI 设计流程之一: Functional Map (以 Axure RP 实作)

有了 User Story,已经能够了解产品会有哪些角色、他们的需求及功能价值。但缺少的是这些需求...

Clean Code系列笔记-原则篇

本文同步发表於个人部落格 前言: 近期在开发公司内部产品系统时,写完後再进行功能测试时,往往会遇到蛮...

Day 27 - State Monad II

在上一章,我们提到了如何用一般方法实作 PRNG 乱数生成器,本章将介绍 State Monad 以...