测试 Rx Java 间隔

Jam*_*mal 4 android unit-testing rx-android rx-java2

我在 ViewModel 中有一个重复的可观察对象,如下所示:

class MainViewModel @Inject constructor(private val ratesUseCase: RatesUseCase) : ViewModel() {

    private var disposable: Disposable? = null
    private val resultLiveData = MutableLiveData<Resource<Map<String, Double>>>()

    fun result() = resultLiveData
    fun getRates(base: String) {
        disposable = Observable
            .interval(1, TimeUnit.SECONDS)
            .flatMap { ratesUseCase.execute(base) }
            .doOnSubscribe { publishResult(Resource.loading(mapOf())) }
            .subscribe(
                {
                    publishResult(Resource.success(values))
                },
                {
                    publishResult(Resource.error(it.localizedMessage, mapOf()))
                }
            )
    }

}
Run Code Online (Sandbox Code Playgroud)

我想测试 getRates 函数。它总是返回 LOADING 状态 这里缺少什么?

测试用例 :

@Test
    fun executeSuccess() {
        val base = "CANARY"
        whenever(currencyRepository.getRates(base))
            .thenReturn(Observable.just(map))

        viewModel.result().observeForever(observer)
        viewModel.getRates(base)
        verify(observer).onChanged(Resource.success(map))
    }
Run Code Online (Sandbox Code Playgroud)

Tub*_*uby 8

如果你不传递SchedulerObservable.interval.

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.COMPUTATION)
public static Observable<Long> interval(long period, TimeUnit unit) {
    return interval(period, period, unit, Schedulers.computation());
}
Run Code Online (Sandbox Code Playgroud)

它将Schedulers.computation()用作默认调度程序。

您的测试线程将完成,而interval不会发出任何内容。

你必须用来TestScheduler正确测试间隔。请参阅此处: 单元测试具有延迟的 Rxjava 可观察量

您可以覆盖计算调度程序或传递TestSchedulerObservable.interval您的 ViewModel。然后你可以TestScheduler.advanceTimeBy控制你的间隔排放。


Jam*_*mal 5

我确实在这里修复了测试,这就是我是如何做到的。这里有两个可观察的:

1- 可观察interval()1秒。

2- 可观察到的ratesUseCase.execute(base)。正如你在下面看到的,它是如何在里面MainViewModel

        Observable
        .interval(1, TimeUnit.SECONDS)
        .flatMap { ratesUseCase.execute(base) }
        .doOnSubscribe { publishResult(Resource.loading(mapOf())) }
        .subscribe(
            {
                publishResult(Resource.success(values))
            },
            {
                publishResult(Resource.error(it.localizedMessage, mapOf()))
            }
        )
Run Code Online (Sandbox Code Playgroud)

为了测试getRatesMainViewModel

1-注入测试调度程序 ratesUseCase.execute(base)

2-RxJavaPlugins.setComputationSchedulerHandler用于更改默认调度程序如下

@Before
fun setUp() {
    val testScheduler = TestScheduler()
    RxJavaPlugins.setComputationSchedulerHandler { testScheduler }

    ratesUseCase = RatesUseCase(appSchedulers, currencyRepository)
    viewModel = MainViewModel(ratesUseCase)
}
Run Code Online (Sandbox Code Playgroud)

3-testScheduler.advanceTimeTo用于测试interval。请不要这里的顺序很重要,如下所示:

3.a : 模拟仓库

3.b : 观察 ViewModel LiveData

3.c:提前时间间隔

3.d : 验证结果

    val base = "BASE"
    whenever(currencyRepository.getRates(base))
        .thenReturn(Observable.just(map))

    viewModel.result().observeForever(observer)
    viewModel.getRates(base)

    testScheduler.advanceTimeTo(1, TimeUnit.SECONDS)
    verify(observer).onChanged(
        Resource.success(map)
    )
Run Code Online (Sandbox Code Playgroud)

完整的项目和测试用例可以在这里找到