单元测试 RxJava 超时未订阅

Posted

技术标签:

【中文标题】单元测试 RxJava 超时未订阅【英文标题】:Unit test RxJava with timeout not subscribe 【发布时间】:2021-12-18 19:33:01 【问题描述】:

我有单元测试函数 RxJava 超时,但它不订阅单元测试。 viewModel 上的函数

fun loadData() 
    loadDataUseCase.loadData(true)
        .subscribeOn(Schedulers.io())
        .timeout(30L, TimeUnit.SECONDS, schedulers)
        .observeOn(androidSchedulers.mainThread())
        .doOnSubscribe 
            onShowLoading.value = true
            onShowError.value = false
            onShowContent.value = false
        .subscribe(
            
                onConnected.value = true
                onShowContent.value = true
                onShowError.value = false
                onShowLoading.value = false
            ,
            
                onShowError.value = true
                onShowLoading.value = false
                onShowContent.value = false
            
        )
        .addTo(compositeDisposable)

单元测试函数

@Test
fun `Load data is success`() 
    // given
    whenever(loadDataUseCase.loadData(true)).thenReturn(Observable.just(true))

    // when
    viewModel.loadData()

    // then
    viewModel.onShowError().test().assertValue(false).awaitNextValue().assertValue(false)

我尝试调试这个函数,但它没有调用订阅

【问题讨论】:

你为什么要对 RxJava 进行单元测试? 【参考方案1】:

我有点迷糊,onShowError()是什么,它返回的是LiveData吗?

如果我运行相同的代码,测试甚至都没有完成(我只使用 io 调度程序和 postValue),对你来说,它可能在订阅发生之前就完成了:

由于您依赖Schedulers.io(),因此您的整个订阅可能在您测试 LiveData 之前就已完成。

另一个选项是您的 LiveData 已经有一个错误值:.assertValue(false)。那么下一个.doOnSubscribe 设置已经触发.awaitNextValue() 并且你的整个测试在订阅被调用之前就完成了。

您的测试应该是固定的,而不是依赖于时间。或者,如果这是不可避免的,那么您必须以某种方式同步您的测试,这里有一个示例:

@Timeout(1, unit = TimeUnit.SECONDS)
@Test
fun `Load data is success`() 
    // given
    whenever(loadDataUseCase.loadData(true)).thenReturn(Observable.just(true)
        
    val testObserver = liveData.test()
    testObserver.assertNoValue() // assert in correct state before actions
    
    // when
    loadData(liveData, mock)
    
    //then
    testObserver.awaitValueHistorySize(2)
        .assertValueHistory(false, false)


fun <T> TestObserver<T>.awaitValueHistorySize(count: Int, delay: Long = 10): TestObserver<T> 
    awaitValue()
    while (valueHistory().size < count) 
        // we need to recheck and don't block, the value we are trying to wait might already arrived between the while condition and the awaitNextValue in the next line, so we use some delay instead.
        awaitNextValue(delay, TimeUnit.MILLISECONDS)
    
    return this

【讨论】:

以上是关于单元测试 RxJava 超时未订阅的主要内容,如果未能解决你的问题,请参考以下文章

用于测试 rxjava 的书面单元测试,但不确定我的单元测试是不是正在测试所有内容

单元测试 RxJava onComplete、onNext 和 onError

RxJava 和改造的单元测试

使用 Completable.timer 对 RxJava 进行单元测试

对有延迟的 Rxjava 可观察对象进行单元测试

在RxJava的doOnSuccess运算符中调用了单元测试验证方法