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 而言😆)