单元测试中 Kotlin Result<T> 的问题

Jos*_*llo 7 android unit-testing kotlin

我正在开发一个 Android 应用程序,我选择使用 Kotlin Result 类来处理我的操作的成功/失败。我对代码进行了更改,但测试停止工作,我不明白为什么。下面我给大家展示一些片段:

FireStoreClient.kt

suspend fun items(): Result<ItemsResponse>
Run Code Online (Sandbox Code Playgroud)

网络数据源.kt

suspend fun getItems(): List<Item> =
    fireStoreClient.items().fold({ it.items.map { item -> item.toDomain() } }, { emptyList() })
Run Code Online (Sandbox Code Playgroud)

网络数据源测试.kt

@ExperimentalCoroutinesApi
@Test
fun `Check getItems works properly`() = runBlockingTest {
    whenever(fireStoreClient.items()).doReturn(success(MOCK_ITEMS_DOCUMENT))
    val expectedResult = listOf(
        Item(
            id = 1,
            desc = "Description 1"
        ),
        Item(
            id = 2,
            desc = "Description 2"
        )
    )
    assertEquals(expectedResult, dataSource.getItems())
}
Run Code Online (Sandbox Code Playgroud)

这是我现在遇到的例外。有什么线索吗?单元测试时似乎未执行 Fold() 方法。

java.lang.ClassCastException: kotlin.Result cannot be cast to ItemsResponse

    at NetworkDataSource.getItems(NetworkDataSource.kt:31)
Run Code Online (Sandbox Code Playgroud)

Mic*_*chD 5

对于那些不想创建自己的Result类型的人,我找到了解决此结果包装问题的不同解决方法。

这个问题似乎在使用 Mockito 的.thenReturnonsuspend函数时特别发生。我发现使用.thenAnswer不会出现问题。

因此,不要在单元测试中编写此内容(更改doReturnthenReturn此处):

whenever(fireStoreClient.items()).thenReturn(success(MOCK_ITEMS_DOCUMENT))
Run Code Online (Sandbox Code Playgroud)

使用:

whenever(fireStoreClient.items()).thenAnswer { success(MOCK_ITEMS_DOCUMENT) }
Run Code Online (Sandbox Code Playgroud)

编辑:我应该注意到,在运行 Kotlin 1.5.0 时我仍然遇到这个问题。

编辑:在 Kotlin 1.5.20 上我可以.thenReturn再次使用。


Pat*_*iak 2

我遇到过同样的问题。

我注意到我应该返回的注入类的方法Result<List<Any>>实际上返回了Result<Result<List<Any>>>,这导致了ClassCastException. 我使用了Evaluate Expression该方法的结果选项,我得到了

Success(Success([]))
Run Code Online (Sandbox Code Playgroud)

该应用程序运行良好,但由于此问题,单元测试未通过。

作为临时解决方案,我构建了一个Result具有扩展功能的密封类的新简单实现fold()。以后应该很容易更换kotlin.Result

Result密封等级:

sealed class Result<T> {
    data class Success<T>(val value: T) : Result<T>()
    data class Failure<T>(val error: Throwable) : Result<T>()
}
Run Code Online (Sandbox Code Playgroud)

fold()扩展功能:

inline fun <R, T> Result<T>.fold(
    onSuccess: (value: T) -> R,
    onFailure: (exception: Throwable) -> R
): R = when (this) {
    is Result.Success -> onSuccess(value)
    is Result.Failure -> onFailure(error)
}
Run Code Online (Sandbox Code Playgroud)