iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0

今天會為上一篇所寫的兩個 use case 加上 unit test。

GetLinesAndStationsUseCaseImplTest

這個 test 其實很簡單,因為本身就是直接把 EtaRepository 拿到的 Map return 出去,所以 unit test 我們只需 mock EtaRepository 的 getLinesAndStations 然後檢查 use case return 出來的 map 是不是跟我們 mock 出來的 getLinesAndStations return value 是否一致即可。

private val DUMMY_DATA = mapOf(
    Line.AEL to setOf(Station.HOK, Station.KOW),
    Line.TKL to setOf(Station.NOP, Station.YAT, Station.LHP),
)

class GetLinesAndStationsUseCaseImplTest {

    private lateinit var useCase: GetLinesAndStationsUseCase

    @MockK
    private lateinit var repository: EtaRepository

    @Before
    fun setUp() {
        MockKAnnotations.init(this)
        useCase = GetLinesAndStationsUseCaseImpl(repository)
        every { repository.getLinesAndStations() } returns DUMMY_DATA

    }

    @Test
    fun invoke() {
        expectThat(useCase()).isEqualTo(DUMMY_DATA)
    }
}

GetEtaUseCaseImplTest

另一個 unit test 是關於車站班次,基本上都是左手交右手(把 EtaRepository return 出來的東西直接 return 給 ViewModel 用),唯獨是在 EtaResult.Success 時我們會再排序。所以我們這次測試的重點會落在 EtaResult.Success 的情景。首先是測試按行車方向排序:

class GetEtaUseCaseImplTest {

    private lateinit var useCase: GetEtaUseCase

    @MockK
    private lateinit var repository: EtaRepository

    @Before
    fun setUp() {
        MockKAnnotations.init(this)
        useCase = GetEtaUseCaseImpl(repository)
    }

    @Test
    fun `success, sort by direction`() = runBlockingTest {
        coEvery {
            repository.getEta(
                Language.ENGLISH,
                Line.TCL,
                Station.OLY
            )
        } returns EtaResult.Success(
            schedule = listOf(
                EtaResult.Success.Eta(
                    direction = EtaResult.Success.Eta.Direction.DOWN,
                    platform = "1",
                    time = Instant.ofEpochSecond(1630700001),
                    destination = Station.HOK,
                    sequence = 2,
                ),
                EtaResult.Success.Eta(
                    direction = EtaResult.Success.Eta.Direction.UP,
                    platform = "1",
                    time = Instant.ofEpochSecond(1630700002),
                    destination = Station.TSY,
                    sequence = 2,
                ),
                EtaResult.Success.Eta(
                    direction = EtaResult.Success.Eta.Direction.UP,
                    platform = "1",
                    time = Instant.ofEpochSecond(1630700002),
                    destination = Station.TUC,
                    sequence = 1,
                ),
                EtaResult.Success.Eta(
                    direction = EtaResult.Success.Eta.Direction.DOWN,
                    platform = "1",
                    time = Instant.ofEpochSecond(1630700004),
                    destination = Station.KOW,
                    sequence = 1,
                ),
            ),
        )
        val result =
            useCase.invoke(Language.ENGLISH, Line.TCL, Station.OLY, GetEtaUseCase.SortBy.DIRECTION)
        expectThat(result).isA<EtaResult.Success>().get(EtaResult.Success::schedule).hasSize(4)
            .and {
                get(0).get(EtaResult.Success.Eta::destination).isEqualTo(Station.TUC)
                get(1).get(EtaResult.Success.Eta::destination).isEqualTo(Station.TSY)
                get(2).get(EtaResult.Success.Eta::destination).isEqualTo(Station.KOW)
                get(3).get(EtaResult.Success.Eta::destination).isEqualTo(Station.HOK)
            }
    }
}

這次我們偷懶,我們把四筆班次的目的地 destination 都設定成不同車站,然後只檢查車站就知道順序是否正確。第二和第三筆班次是用來測試當時間相同時會不會按序號 sequence 排列。

另一個 test case 是測試按時間排序。跟剛才的 success, sort by direction test case 一樣,我們都是借 destination 判斷排序是否正確。留意第一及第二筆的時間 time 都是相同,目的是檢查結果是否有按序號 sequence 排列。

@Test
fun `success, sort by time`() = runBlockingTest {
    coEvery {
        repository.getEta(
            Language.ENGLISH,
            Line.TCL,
            Station.OLY
        )
    } returns EtaResult.Success(
        schedule = listOf(
            EtaResult.Success.Eta(
                direction = EtaResult.Success.Eta.Direction.DOWN,
                platform = "1",
                time = Instant.ofEpochSecond(1630700001),
                destination = Station.HOK,
                sequence = 2,
            ),
            EtaResult.Success.Eta(
                direction = EtaResult.Success.Eta.Direction.UP,
                platform = "1",
                time = Instant.ofEpochSecond(1630700001),
                destination = Station.TUC,
                sequence = 1,
            ),
            EtaResult.Success.Eta(
                direction = EtaResult.Success.Eta.Direction.UP,
                platform = "1",
                time = Instant.ofEpochSecond(1630700004),
                destination = Station.TSY,
                sequence = 2,
            ),
            EtaResult.Success.Eta(
                direction = EtaResult.Success.Eta.Direction.DOWN,
                platform = "1",
                time = Instant.ofEpochSecond(1630700003),
                destination = Station.KOW,
                sequence = 1,
            ),
        ),
    )
    val result =
        useCase.invoke(Language.ENGLISH, Line.TCL, Station.OLY, GetEtaUseCase.SortBy.TIME)
    expectThat(result).isA<EtaResult.Success>().get(EtaResult.Success::schedule).hasSize(4)
        .and {
            get(0).get(EtaResult.Success.Eta::destination).isEqualTo(Station.TUC)
            get(1).get(EtaResult.Success.Eta::destination).isEqualTo(Station.HOK)
            get(2).get(EtaResult.Success.Eta::destination).isEqualTo(Station.KOW)
            get(3).get(EtaResult.Success.Eta::destination).isEqualTo(Station.TSY)
        }
}

除了 EtaResult.Success 外,我們還會為其他情況寫 test case,下面是 EtaResult.Incident 的 test case:

@Test
fun incident() = runBlockingTest {
    val incident = EtaResult.Incident("Out of order!", "http://example.com")
    coEvery {
        repository.getEta(
            Language.ENGLISH,
            Line.TCL,
            Station.OLY
        )
    } returns incident
    val result =
        useCase.invoke(Language.ENGLISH, Line.TCL, Station.OLY, GetEtaUseCase.SortBy.DIRECTION)
    expectThat(result).isEqualTo(incident)
}

基本上都是比對 return value 是不是跟 EtaRepository return 出來的一樣,其餘的 test case 都是同樣寫法,所以我就不逐一貼出來。完整的 test class 可以到 GitHub repo 查看。

下一篇我們會開始做 presentation layer。


上一篇
Domain layer implementation
下一篇
Navigation (1)
系列文
寫一個列車抵站時間 Android App 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言