🧪

Kotlin FlowのエラーケースのUnit testでハマって解消した

2023/11/04に公開

事象

kotlin.testMockKTubineを使用して

interface UserRepository {
    fun observeUsers(): Flow<Result<List<User>>>
}

のようなFlowを返す関数をラップしたObserveUsersUseCaseのテストコードを

@Test
fun observeUsers_failure() {
    coEvery { userRepository.observeUsers() } throws Exception("result failure")
    runTest {
        val result = observeUsersUseCase()
        coVerify(exactly = 1) { userRepository.observeUsers() }
        result.test {
            assertIs<Result.Error>(awaitItem())

            awaitComplete()
        }
    }
}

このような感じに書いていたのですが、

java.lang.Exception: result failure

ってそのままExceptionが出てしまいテストが失敗していました。

対応

- coEvery { userRepository.observeUsers() } throws Exception("result failure")
+ coEvery { userRepository.observeUsers() } returns flow { Exception("result failure") }

が正解でした。
そもそもFlowの中でExceptionが出る訳なんだけど、ハマると分からなくなるよねって話でした。

余談:kotlin.test便利

kotlin.testのassertIs<T>()って便利ですね
今までJUnitを使っていたので↓みたいに書いてました。

assert(awaitItem() is Result.Error)

まぁ以前、参画していたプロジェクトではKotestを使用していたのでshouldBeTypeOf<T>()を使っていましたが、公式のkotlin.testでサポートされてる方が今後何かと便利ですよねー。

参考

https://kotlinlang.org/api/latest/kotlin.test/
https://mockk.io/
https://github.com/cashapp/turbine
https://kotest.io/

Discussion