2017-04-07 2 views
8

Ich versuche, die folgende RxKotlin/RxJava 2 Code zu testen:RxJava 2 übergeordnete IO-Scheduler in Unit-Test

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

Ich versuche, die Disponenten außer Kraft zu setzen, wie folgt:

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

ich erhalte jedoch die folgende Fehlermeldung, wenn die Durchführung des Tests:

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) 

Hat jemand dieses Problem erfahren?


Der Test funktionierte gut, wenn RxKotlin/RxJava 1 und die folgenden Scheduler überschreibt mit:

Dank!

+1

Siehe das aktualisierte Javadoc für 2.0.8: http://reactivex.io/RxJava/2.x/ javadoc/io/reactivex/schedulers/Schedulers.html # io() – akarnokd

+1

Insbesondere "Beachten Sie, dass aufgrund der möglichen Initialisierungszyklen, mit einer der anderen Scheduler-Rückgabe-Methoden zu einer NullPointerException führen." – Kiskae

+1

"Sobald die Schedulers-Klasse initialisiert wurde, können Sie die zurückgegebene Scheduler-Instanz über die RxJavaPlugins.setIOSchedulerHandler (io.reactivex.functions.Function) -Methode überschreiben." – akarnokd

Antwort

17

Ich schlage vor, dass Sie einen anderen Ansatz wählen und Ihren Schedulern eine Abstraktionsebene hinzufügen. Dieser Kerl hat einen schönen Artikel darüber: https://medium.com/@peter.tackage/an-alternative-to-rxandroidplugins-and-rxjavaplugins-scheduler-injection-9831bbc3dfaf

es so etwas wie dies in Kotlin

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

aussehen würde und Sie dann mit Ihrer eigenen Implementierung von SchedulerProvider außer Kraft setzen, dass:

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

Und ein für Testklassen:

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

Ihr Code würde aussehen wie dieser, wo Sie RxJava nennen:

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

Und Sie werden nur Ihre Implementierung von SchedulerProvider außer Kraft setzen, basierend auf, wo Sie es testen. Hier ist ein Beispielprojekt als Referenz, ich bin die Testdatei verknüpfen, die die testbare Version von SchedulerProvider verwenden würde: https://github.com/Obaied/DingerQuotes/blob/master/app/src/test/java/com/obaied/dingerquotes/QuotePresenterTest.kt#L31

+0

Danke für den Austausch von "Trampolin". Ich habe "sofort" verwendet, aber es ist nicht mehr in Rx2 verfügbar –

+0

Ja. Du hast Recht. Ich werde meine Antwort aktualisieren, um auch Rx2 zu reflektieren – Solidak

+0

Ich meinte, im Gegenteil, in Rx2 gibt es keine unmittelbare. Nur Trampolin. –

3

Ich habe es herausgefunden! Es hatte mit der Tatsache zu tun, dass in diesem Code:

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

validate(data) war ein Observable Rückkehr, die die folgenden ausstrahlte: emitter.onNext(null). Da RxJava 2 keine null Werte mehr akzeptiert, wurde flatMap nicht aufgerufen. Ich änderte validate den Scheduler überschreiben die folgenden ein Completable und aktualisiert zurückzukehren:

RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() } 

Nun sind die Tests bestanden!