Тестирование Rx Java интервал - PullRequest
0 голосов
/ 14 января 2019

У меня есть повторяемая наблюдаемая внутри 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()))
                }
            )
    }

}

Я хочу проверить функцию getRates. Это всегда возвращает статус загрузки Чего здесь не хватает?

Контрольный пример:

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

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Я исправил тесты, вот как я это сделал. здесь можно наблюдать две:

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

Для проверки getRates в MainViewModel

1 - Inject Test расписания для ratesUseCase.execute(base)

2- Используйте RxJavaPlugins.setComputationSchedulerHandler, чтобы изменить планировщик по умолчанию, как показано ниже

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

    ratesUseCase = RatesUseCase(appSchedulers, currencyRepository)
    viewModel = MainViewModel(ratesUseCase)
}

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

Полный проект и тестовые примеры можно найти здесь

0 голосов
/ 14 января 2019

Вот что произойдет, если вы не передадите Scheduler на Observable.interval.

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

Он будет использовать Schedulers.computation() в качестве планировщика по умолчанию.

Ваша тестовая нить просто закончится, пока interval не сможет ничего испустить.

Вы должны использовать TestScheduler, чтобы правильно проверить интервал. Посмотреть здесь: Юнит-тестирование наблюдаемых Rxjava с задержкой

Вы можете переопределить планировщик вычислений или передать TestScheduler в Observable.interval в вашей ViewModel. Тогда вы можете TestScheduler.advanceTimeBy и контролировать интервал выбросов.

...