TestScheduler

TestSchedulers 允许你控制 Observables 的时间和执行,而不必进行繁忙的等待,加入线程或任何操作系统时间。如果你想编写可预测,一致且快速的单元测试,这非常重要。因为你正在操作时间,所以线程不再有机会,你的测试在较慢的机器上失败,或者浪费执行时间忙于等待结果。

可以通过重载提供 TestSchedulers,该重载将调度程序用于任何 RxJava 操作。

TestScheduler testScheduler = new TestScheduler();
TestSubscriber<Integer> subscriber = TestSubscriber.create();
Observable.just(1,2,3)
          .delay(10, TimeUnit.SECONDS, testScheduler)
          .subscribe(subscriber);

try {
    Thread.sleep(TimeUnit.SECONDS.toMillis(11));
} catch (InterruptedException ignored) { }
subscriber.assertValues(1,2,3); // fails

testScheduler.advanceTimeBy(10, TimeUnit.SECONDS);
subscriber.assertValues(1,2,3); // success

TestScheduler 非常基础。它只包含三种方法。

testScheduler.advanceTimeBy(amount, timeUnit);
testScheduler.advanceTimeTo(when, timeUnit);
testScheduler.triggerActions();

这使你可以在 TestScheduler 应该触发将来某个时间的所有操作时进行操作。

在传递调度程序时,这不是 TestScheduler 的常用方法,因为它的效率低。将调度程序传递给类最终会提供大量额外代码以获得很少的收益。相反,你可以挂钩到 RxJava 的 Schedulers.io()/ computation()/ etc。这是通过 RxJava 的 Hooks 完成的。这使你可以定义从其中一个 Scheduler 方法调用返回的内容。

public final class TestSchedulers {

    public static TestScheduler test() {
        final TestScheduler testScheduler = new TestScheduler();
        RxJavaHooks.reset();
        RxJavaHooks.setOnComputationScheduler((scheduler) -> {
            return testScheduler;
        });
        RxJavaHooks.setOnIOScheduler((scheduler) -> {
            return testScheduler;
        });
        RxJavaHooks.setOnNewThreadScheduler((scheduler) -> {
            return testScheduler;
        });
        return testScheduler;
    }
}

此类允许用户获取将连接到调度程序的所有调用的测试调度程序。单元测试只需要在其设置中获得此调度程序。强烈建议在设置中查询它而不是任何普通的旧字段,因为你的 TestScheduler 可能会在你提前时间时尝试从另一个单元测试中触发操作。现在我们的例子变成了

TestScheduler testScheduler = new TestScheduler();
TestSubscriber<Integer> subscriber = TestSubscriber.create();
Observable.just(1,2,3)
          .delay(10, TimeUnit.SECONDS, testScheduler)
          .subscribe(subscriber);
testScheduler.advanceTimeBy(9, TimeUnit.SECONDS);
subscriber.assertValues(); // success (delay hasn't finished)
testScheduler.advanceTimeBy(10, TimeUnit.SECONDS);
subscriber.assertValues(1,2,3); // success (delay has finished)

这就是你如何有效地从单元测试中删除系统时钟(至少就 RxJava 而言😆)