【问题标题】:Unit testing RxJava + Retrofit call inside the method方法内部的单元测试 RxJava + Retrofit 调用
【发布时间】:2018-02-09 13:33:28
【问题描述】:

我要测试的方法包含对改造服务的两次调用:

 internal fun poll(): Completable {
    return presenceService.askForFrequency(true).toObservable()
            .flatMap { it -> Observable.interval(it.frequency, TimeUnit.SECONDS, Schedulers.io()) }
            .flatMapCompletable { _ -> presenceService.sendHeartbeat() }
            .subscribeOn(Schedulers.io())
            .retry()
}

presenceService 是在类中注入的,所以我提供了一个模拟的用于测试:

val frequency = PublishSubject.create<Presence>()
val heartbeat = PublishSubject.create<Unit>()
val mockPresenceService = mock<PresenceService> {
    on { askForFrequency(any()) } doReturn frequency
    on { sendHeartbeat() } doReturn heartbeat
}

检查 askForFrequency 方法是否被调用的测试工作正常,但检查轮询请求是否发送的测试永远不会工作:

@Test
fun presenceService_sentHeartbeat() {
    RxJavaPlugins.setIoSchedulerHandler { scheduler }

    frequency.onNext(Presence(1)) //polls with 1s interval
    heartbeat.onNext(Unit)
    presenceMaintainer.onActivityResumed(any())
    scheduler.advanceTimeBy(2, TimeUnit.SECONDS)
    verify(mockPresenceService).askForFrequency(true) //works correctly
    verify(mockPresenceService).sendHeartbeat() //never works
}

单元测试运行的日志是:

Wanted but not invoked:
presenceService.sendHeartbeat();

However, there was exactly 1 interaction with this mock:
presenceService.askForFrequency(true);

问题是:如何测试第二个方法(sendHeartbeat)是否也被调用(可能多次)

同时我发现问题出在第二个平面图中,因为对该方法的测试工作正常(验证该方法被调用了 60 次):

 internal fun pollTest(): Observable<Presence> {
    return Observable.interval(1, TimeUnit.SECONDS, Schedulers.io())
            .subscribeOn(Schedulers.io())
            .flatMap { it -> presenceService.askForFrequency(true).toObservable() }
}

@Test
fun presenceService_sentHeartbeat() {
    frequency.onNext(Presence(1))
    val result = arrayListOf<Unit>()
    presenceMaintainer.pollTest().subscribe({ t -> result.add(Unit) })
    Thread.sleep(60*1000)
    println(result.size)
    verify(mockPresenceService, Times(60)).askForFrequency(true)
}

但是当我将调用顺序更改为askForFrequency -&gt; map to interval -&gt; map each tick to poll call 时,测试停止工作,并且只调用一次模拟。

【问题讨论】:

    标签: android unit-testing mockito retrofit2 rx-java2


    【解决方案1】:

    默认情况下,Observable.interval() 在计算调度程序上运行,而不是在 io 调度程序上运行。这意味着,2 秒的等待将实时运行,因此您的测试将在调用 sendHeartBeat() 前 2 秒完成。

    【讨论】:

    • 谢谢!但是如果我在间隔调用中添加RxJavaPlugins.setComputationSchedulerHandler { scheduler }或指定Schedulers.io,它也不起作用。
    • 虽然设置起来可能很痛苦,但我自己的经验是传递 interval()delay()debounce() 操作员将在其上运行的调度程序。它使测试变得更加容易。
    猜你喜欢
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多