【问题标题】:Unit Testing CoroutineExceptionHandler单元测试 CoroutineExceptionHandler
【发布时间】:2019-10-04 13:48:32
【问题描述】:

您好,我有这段使用协程的代码,我想对其进行单元测试:

我的问题是我的异常从未被CoroutineExceptionHandler 捕获。

我的代码如下所示:

 fun request() {
    val handler = CoroutineExceptionHandler { _, throwable -> liveData.value = Resource.error(throwable.message) }

    viewModelScope.launch(handler) {
        liveData.value = Resource.loading()
        val result = withContext(Dispatchers.IO) { useCase.request() }
        liveFdDetails.value = Resource.success(result)
    }
}

还有我的测试:

fun testError() = runBlocking {

    //Given
    val observer: Observer<Resource<Data>> = mock()
    whenever(useCase.request()).thenThrow(Error("MSG"))
    viewModel.liveData.observeForever(observer)

    //When
    viewModel.request()

    //Then
    inOrder(observer).apply {
        verify(observer).onChanged(Resource.loading())
        verify(observer).onChanged(Resource.error("MSG"))
    }
}

【问题讨论】:

    标签: android unit-testing kotlin coroutine kotlin-coroutines


    【解决方案1】:
    viewModelScope.launch(handler) {
    

    在这里,您在runBlocking 以外的范围内启动协程。由于它不是它的子协程,runBlocking 不会等待它完成。很可能整个测试在协程有时间在 IO 线程中启动并失败之前完成。

    但是,鉴于您在异常处理程序中的代码,我认为您没有使用正确的工具。

    协程异常处理程序不是用于常规异常处理的机制,它们只是有机会观察您的代码应该处理但不是由于错误引起的异常的最后手段。

    对于业务逻辑级错误处理,使用自然机制try-catch。如果你有很多重复的错误处理逻辑,你总是可以写一个inline fun(block: inline () -&gt; Unit),将块包装在这样的样板try-catch中。

    【讨论】:

    • 要在launch中指定Dispatcher时如何使用handler? viewModelScope.launch(exceptionHandler) {withContext(Dispatchers.IO) {...}} ?
    • launch(handler + IO)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2011-04-12
    • 2023-03-21
    • 2011-05-04
    相关资源
    最近更新 更多