使用RxJava的通用Observable的TestScheduler

时间:2017-10-09 15:29:50

标签: unit-testing rx-java

我开始使用TestScheduler。一切都很好用这样的东西:

@Test
public void test1() throws Exception {
    //when
    TestScheduler scheduler = new TestScheduler();
    TestObserver<Long> subscriber = new TestObserver<>();

    //run
    Observable
            .interval(1L, TimeUnit.SECONDS, scheduler)
            .subscribeWith(subscriber);

    //check
    scheduler.advanceTimeBy(200, TimeUnit.SECONDS);
    assertEquals(200, subscriber.valueCount());
}

如果我改用它:

@Test
public void test2() throws Exception {
    //when
    TestScheduler scheduler = new TestScheduler();
    TestObserver<Long> subscriber = new TestObserver<>();

    //run
    Observable
            .interval(1L, TimeUnit.SECONDS)
            .observeOn(scheduler)
            .subscribeOn(scheduler)
            .subscribeWith(subscriber);

    //check
    scheduler.advanceTimeBy(200, TimeUnit.SECONDS);
    assertEquals(200, subscriber.valueCount());
}

测试失败,因为订阅者从未被调用过。

我找到的所有示例都使用带有TestScheduler的{​​{1}}并将调度程序传递给工厂方法,就像我在第一个示例中所做的那样。 我不能使用这种方法的原因是,在真实应用程序中,可观察量并不像这一样简单,我无法通过调度程序。 我认为设置Observable.interval就好像我在第二个例子中这样做会很好,但看起来它不是。

将TestScheduler用于更通用的Observable的正确方法是什么?

不使用TestScheduler我可以成功使用这些方法:

Scheduler

修改

如果我使用

没有区别
@Test
public void test3() throws Exception {
    //when
    Scheduler trampoline = Schedulers.trampoline();

    //run
    TestObserver<Long> test = Observable
            .interval(1L, TimeUnit.SECONDS)
            .observeOn(trampoline)
            .subscribeOn(trampoline)
            .test();

    //check
    test.await(3100,TimeUnit.MILLISECONDS);
    assertEquals(3, test.valueCount());
}

@Test
public void test4() throws Exception {
    //when
    Scheduler trampoline = Schedulers.trampoline();

    //run
    TestObserver<Long> test = Observable
            .fromArray(1L, 2L, 3L)
            .subscribeOn(trampoline)
            .observeOn(trampoline)
            .test();

    //check
    assertEquals(3, test.valueCount());
}

@Test
public void test5() throws Exception {
    //when
    Scheduler trampoline = Schedulers.trampoline();

    //run
    TestObserver<Long> test = Observable
            .fromArray(1L, 2L, 3L)
            .subscribeOn(trampoline)
            .observeOn(AndroidSchedulers.mainThread())
            .test();

    //check
    test.awaitTerminalEvent();
    assertEquals(3, test.valueCount());
}

1 个答案:

答案 0 :(得分:2)

如果要覆盖可能使用的标准调度程序(用于间隔)。也可以覆盖其他标准调度程序。

RxJavaPlugins.setComputationSchedulerHandler(scheduler -> testScheduler);

testScheduler 将是您的TestScheduler。设置插件后,您可以像 test1

中一样使用advanceTime

示例:

@Test
// fails because interval schedules on different thread then JUnit-Runner-thread -> fall through
void notWorkingTest1() throws Exception {
    TestScheduler scheduler = new TestScheduler();
    TestObserver<Long> subscriber = new TestObserver<>();

    Observable
            .interval(1L, TimeUnit.SECONDS)
            .observeOn(scheduler)
            .subscribeOn(scheduler)
            .subscribeWith(subscriber);

    //check
    scheduler.advanceTimeBy(200, TimeUnit.SECONDS);
    assertEquals(200, subscriber.valueCount());
}


@Test
// not working because interval will not be scheduled on virtual time -> JUnit-Runner-Thread will close because test observable emits on different thread
void notWorkingTest2() throws Exception {
    //when
    TestScheduler scheduler = new TestScheduler();

    //run
    TestObserver<Long> test = Observable
            .interval(1L, TimeUnit.SECONDS)
            .observeOn(scheduler)
            .subscribeOn(scheduler)
            .test();

    scheduler.advanceTimeBy(200, TimeUnit.SECONDS);

    test.assertValueCount(200);
}

@Test
// runs sync. -> no JUnit-Runner-thread blocking needed
void workingTest() throws Exception {
    TestScheduler scheduler = new TestScheduler();
    RxJavaPlugins.setComputationSchedulerHandler(s -> scheduler);

    TestObserver<Long> test = Observable
            .interval(1L, TimeUnit.SECONDS) // executed on Schedulers.computation()
            .observeOn(scheduler)
            .subscribeOn(scheduler)
            .test();

    scheduler.advanceTimeBy(200, TimeUnit.SECONDS);

    test.assertValueCount(200);
}