=================
== The Archive ==
=================

테스트 코드에서 시간을 자유롭게 다뤄보자

|

개요

Clock Wrapper 를 사용하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Clock {
    fun now(): LocalDate = LocalDate.now()
}

class ChristmasDiscount(
    private val clock: Clock, // Clock 을 가져다가 쓰도록 한다.
) {
    fun applyDiscount(rawAmount: Double): Double {
        val today: LocalDate = clock.now()

        var discountPercentage = 0.0
        val isChristmas = today.month == Month.DECEMBER && today.dayOfMonth == 25

        if (isChristmas) discountPercentage = 0.15

        return rawAmount - (rawAmount * discountPercentage)
    }
}

class ChristmasDiscountTest {
    private val clock: Clock = mockk<Clock>()
    private val sut = ChristmasDiscount(clock)

    @Test
    fun christmas() {
        val christmas: LocalDate = LocalDate.of(2015, Month.DECEMBER, 25)
        every { clock.now() } returns christmas // ClockWrapper 를 mocking 하여 사용하면 된다.

        val finalValue = sut.applyDiscount(100.0)
        assertThat(finalValue).isCloseTo(85.0, offset(0.001))
    }

    @Test
    fun notChristmas() {
        val notChristmas: LocalDate = LocalDate.of(2015, Month.DECEMBER, 26)
        every { clock.now() } returns notChristmas

        val finalValue = sut.applyDiscount(100.0)
        assertThat(finalValue).isCloseTo(100.0, offset(0.001))
    }
}

Clock Wrapper 없이 사용하기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class ChristmasDiscountWithoutClock {
    fun applyDiscount(rawAmount: Double): Double {
        val today: LocalDate = LocalDate.now()

        var discountPercentage = 0.0
        val isChristmas = today.month == Month.DECEMBER && today.dayOfMonth == 25

        if (isChristmas) discountPercentage = 0.15

        return rawAmount - (rawAmount * discountPercentage)
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class ChristmasDiscountWithoutClockTest {
    private val sut = ChristmasDiscountWithoutClock()

    @Test
    fun christmas() {
        val christmas: LocalDate = LocalDate.of(2015, Month.DECEMBER, 25)

        val finalValue =
            resetClock(christmas) {
                sut.applyDiscount(100.0)
            }

        assertThat(finalValue).isCloseTo(85.0, offset(0.001))
    }

    @Test
    fun notChristmas() {
        val notChristmas: LocalDate = LocalDate.of(2015, Month.DECEMBER, 26)

        val finalValue =
            resetClock(notChristmas) {
                sut.applyDiscount(100.0)
            }

        assertThat(finalValue).isCloseTo(100.0, offset(0.001))
    }
}

fun <T> resetClock(
    targetLocalDate: LocalDate,
    block: () -> T,
): T {
    mockkStatic(LocalDate::class)
    every { LocalDate.now() } returns targetLocalDate
    return block.invoke().also { unmockkStatic(LocalDate::class) }
}

References

Categories:

Tags: