Search code examples
androidunit-testingrx-java2rx-android

Testing Rx Java interval


I have a repeated observable inside a ViewModel as below:

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()))
                }
            )
    }

}

I want to test getRates function. It always return LOADING status What is missing here?

Test case :

@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))
    }

Solution

  • Thats what happens if you don't pass Scheduler to Observable.interval.

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

    It will use Schedulers.computation() as default Scheduler.

    Your test thread will just finish while interval will not manage to emit anything.

    You have to you use TestScheduler to test interval properly. See here: Unit testing Rxjava observables that have a delay

    You can override computation scheduler or pass TestScheduler to Observable.interval in your ViewModel. Then you can TestScheduler.advanceTimeBy and control your interval emissions.