web-dev-qa-db-fra.com

RxJava 2 écrasant IO ordonnanceur en test unitaire

J'essaie de tester le code RxKotlin/RxJava 2 suivant:

validate(data)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .flatMap { ... }

J'essaie de remplacer les planificateurs comme suit:

// Runs before each test suite
RxJavaPlugins.setInitIoSchedulerHandler { Schedulers.trampoline() }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }

Cependant, le message d'erreur suivant s'affiche lors de l'exécution du test:

Java.lang.ExceptionInInitializerError
...
Caused by: Java.lang.NullPointerException: Scheduler Callable result can't be null
    at io.reactivex.internal.functions.ObjectHelper.requireNonNull(ObjectHelper.Java:39)
    at io.reactivex.plugins.RxJavaPlugins.applyRequireNonNull(RxJavaPlugins.Java:1317)
    at io.reactivex.plugins.RxJavaPlugins.initIoScheduler(RxJavaPlugins.Java:306)
    at io.reactivex.schedulers.Schedulers.<clinit>(Schedulers.Java:84)

Quelqu'un a-t-il eu ce problème? 


Le test a fonctionné correctement avec RxKotlin/RxJava 1 et les remplacements de planificateur suivants:

RxAndroidPlugins.getInstance().registerSchedulersHook(object : RxAndroidSchedulersHook() {
    override fun getMainThreadScheduler() = Schedulers.immediate()
})

RxJavaPlugins.getInstance().registerSchedulersHook(object : RxJavaSchedulersHook() {
    override fun getIOScheduler() = Schedulers.immediate()
})

Merci!

15
Alex B

Je vous suggère d’adopter une approche différente et d’ajouter une couche d’abstraction à vos planificateurs. Ce mec a un bel article à ce sujet: https://medium.com/@peter.tackage/an-alternative-to-rxandroidplugins-and-rxjavaplugins-scheduler-injection-9831bbccdfdf

Cela ressemblerait à quelque chose comme ça à Kotlin

interface SchedulerProvider {
    fun ui(): Scheduler
    fun computation(): Scheduler
    fun trampoline(): Scheduler
    fun newThread(): Scheduler
    fun io(): Scheduler }

Et ensuite, vous remplacez cela par votre propre implémentation de SchedulerProvider:

class AppSchedulerProvider : SchedulerProvider {
    override fun ui(): Scheduler {
        return AndroidSchedulers.mainThread()
    }

    override fun computation(): Scheduler {
        return Schedulers.computation()
    }

    override fun trampoline(): Scheduler {
        return Schedulers.trampoline()
    }

    override fun newThread(): Scheduler {
        return Schedulers.newThread()
    }

    override fun io(): Scheduler {
        return Schedulers.io()
    }
}

Et un pour tester les cours:

class TestSchedulerProvider : SchedulerProvider {
    override fun ui(): Scheduler {
        return Schedulers.trampoline()
    }

    override fun computation(): Scheduler {
        return Schedulers.trampoline()
    }

    override fun trampoline(): Scheduler {
        return Schedulers.trampoline()
    }

    override fun newThread(): Scheduler {
        return Schedulers.trampoline()
    }

    override fun io(): Scheduler {
        return Schedulers.trampoline()
    }
}

Votre code ressemblerait à ceci lorsque vous appelez RxJava:

mCompositeDisposable.add(mDataManager.getQuote()
        .subscribeOn(mSchedulerProvider.io())
        .observeOn(mSchedulerProvider.ui())
        .subscribe(Consumer<Quote> {
...

Et vous allez simplement annuler votre implémentation de SchedulerProvider en fonction de l'endroit où vous l'avez testée. Voici un exemple de projet à titre de référence. Je relie le fichier de test qui utiliserait la version testable de SchedulerProvider: https://github.com/Obaied/DingerQuotes/blob/master/app/src/test/Java/com /obaied/dingerquotes/QuotePresenterTest.kt#L31

23
Solidak

Deviner! Cela avait à voir avec le fait que dans ce code:

validate(data)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .flatMap { ... }

validate(data) retournait une Observable, qui émettait ce qui suit: emitter.onNext(null). Puisque RxJava 2 n'accepte plus les valeurs null, flatMap n'a pas été appelé. J'ai changé validate pour renvoyer Completable et mis à jour le remplacement du planificateur comme suit:

RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }

Maintenant les tests sont réussis!

10
Alex B