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

Posted

技术标签:

【中文标题】使用 Completable.timer 对 RxJava 进行单元测试【英文标题】:Unit testing RxJava with a Completable.timer 【发布时间】:2020-03-07 07:28:08 【问题描述】:
android Studio 3.5.2
RxJava2
Kotlin 1.3.50

我有一个像计时器一样的类。

class DelayTimerImp(private val scheduler: IScheduler)
    : DelayTimer 

    override fun createTimeout(delay: Long, timeUnites: TimeUnit): Completable 
        return Completable.timer(delay, TimeUnit.SECONDS, scheduler.main())
    

我正在以这样的方法使用它:

private fun startTimeoutRequest(delay: Long) 
    compositeSubscription.add(delayTimer.createTimeout(delay, TimeUnit.SECONDS)
            .subscribeOn(schedulers.io())
            .subscribe(::timeoutHasExceeded, ::timeoutError))

在我的测试类中,它使用TestScheduler 返回io 线程。我在嘲笑delayTimer。即使我thenReturn(Completable.complete()) timeOutHasExceeded 中的方法从不涉及它们。我在想如果Completable 已经完成进入那个方法。

@Test
fun `should reload and show loading state`() 
    // Arrange
    whenever(delayTimer.createTimeout(10, TimeUnit.SECONDS))
            .thenReturn(Completable.complete())

    // Act
    vipInformationPresenterImp.tryAgainTapped()

    // Assert methods in the timeOutHasExceeded

另外,如果我通过将延迟更改为 1 来更改以下内容:

whenever(delayTimer.createTimeout(1, TimeUnit.SECONDS))
                .thenReturn(Completable.complete())

我将在以下行收到crash

.subscribeOn(schedulers.io())

对此进行单元测试的最佳方法是什么?

在此先感谢

【问题讨论】:

你打电话给TestScheduler.advanceTimeBy()还是TestScheduler.triggerActions() 【参考方案1】:

根据this tutorial,您应该使用 TestScheduler 覆盖这些:

class TestSchedulerProvider(private val scheduler: TestScheduler) : BaseSchedulerProvider 
    override fun computation() = scheduler
    override fun ui() = scheduler
    override fun io() = scheduler

然后本教程使用 TestScheduler 如下:

@Test
fun delayTestExample() 
    //given
    val presenter = DemoPresenter(testSchedulerProvider, view, service)
    given(service.getSomeRemoteData()).willReturn(Single.just(5))
    val delayInMillis = 1000L

    //when
    presenter.getSomeDataWithDelay(delayInMillis)

    //then
    then(view).should(never()).showData(anyInt())
    // HERE:
    testScheduler.advanceTimeBy(delayInMillis, TimeUnit.MILLISECONDS) 
    then(view).should().showData(5)

advanceTimeBy 的使用在代码中的注释//HERE: 下进行了描述。是否可以使用相同的方法来代替您的:

whenever(delayTimer.createTimeout(1, TimeUnit.SECONDS))
            .thenReturn(Completable.complete())

例如,您可以调用:

testScheduler.advanceTimeBy(1500, TimeUnit.MILLISECONDS)

在您创建超时后的行中,我选择了 1500,以便在advanceTimeBy 继续之前真正在计时器中标记 1 秒。不过,它应该与每个值 > 1000 配合得很好,我只是想确定一下 ;)

【讨论】:

以上是关于使用 Completable.timer 对 RxJava 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

csharp 使用Akka.net对事件进行分区(linqpad - 参考akka.net和Rx-main)

有人在使用 rx.jquery 吗?

静态成员 rx 不能在实例类型 UICollectionView 上使用

茶茶苏妈满血回归,AMD RX 6900XT 测试报告

简讯AMD制定RX 6800系列显卡命名规范;华为海思自研OLED驱动芯片已流片…

Rx响应式编程知多少 - 系列:LINQ和Rx简介