RxJavaをテストする方法は?
1. 概要
この記事では、RxJavaを使用して記述されたコードをテストする方法を見ていきます。
RxJavaで作成している一般的なフローは、 観察可能と
通常、オブザーバブルとオブザーバブルは非同期で別々のスレッドで実行されるため、従来の方法でコードをテストするのは困難です。
幸い、 RxJavaはTestSubscriberクラスを提供し、非同期のイベント駆動型フローをテストする機能を提供します。
2. RxJavaのテスト–従来の方法
例から始めましょう–1からの整数のシーケンスでzipしたい文字のシーケンスがあります。
私たちのテストは、zip形式のobservableによって発行されたイベントをリッスンするサブスクライバーが、整数で圧縮された文字を受信することを表明する必要があります。
従来の方法でこのようなテストを作成するということは、結果のリストを保持し、オブザーバーからそのリストを更新する必要があることを意味します。 整数のリストに要素を追加するということは、オブザーバブルとオブザーバブルが同じスレッドで動作する必要があることを意味します。非同期で動作することはできません。
そのため、RxJavaの最大の利点の1つである、個別のスレッドでのイベントの処理が失われます。
テストの限定バージョンは次のようになります。
List<String> letters = Arrays.asList("A", "B", "C", "D", "E");
List<String> results = new ArrayList<>();
Observable<String> observable = Observable
.from(letters)
.zipWith(
Observable.range(1, Integer.MAX_VALUE),
(string, index) -> index + "-" + string);
observable.subscribe(results::add);
assertThat(results, notNullValue());
assertThat(results, hasSize(5));
assertThat(results, hasItems("1-A", "2-B", "3-C", "4-D", "5-E"));
results リストに要素を追加することにより、オブザーバーからの結果を集約しています。 オブザーバーとオブザーバブルは同じスレッドで動作するため、アサーションは適切にブロックされ、 subscribe()メソッドが終了するのを待ちます。
3. TestSubscriberを使用したRxJavaのテスト
RxJavaにはTestSubsriberクラスが付属しており、イベントの非同期処理で機能するテストを作成できます。 これは、オブザーバブルをサブスクライブする通常のオブザーバーです。
テストでは、 TestSubscriber の状態を調べて、その状態についてアサーションを作成できます。
List<String> letters = Arrays.asList("A", "B", "C", "D", "E");
TestSubscriber<String> subscriber = new TestSubscriber<>();
Observable<String> observable = Observable
.from(letters)
.zipWith(
Observable.range(1, Integer.MAX_VALUE),
((string, index) -> index + "-" + string));
observable.subscribe(subscriber);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(5);
assertThat(
subscriber.getOnNextEvents(),
hasItems("1-A", "2-B", "3-C", "4-D", "5-E"));
TestSubscriberインスタンスをobservableのsubscribe()メソッドに渡します。 次に、このサブスクライバーの状態を調べることができます。
TestSubscriberには、期待を検証するために使用する非常に便利なアサーションメソッドがいくつかあります。 サブスクライバーは、オブザーバーによって5つの放出された要素を受け取る必要があり、 assertValueCount()メソッドを呼び出すことによってそれを表明します。
getOnNextEvents()メソッドを呼び出すことにより、サブスクライバーが受信したすべてのイベントを調べることができます。
assertCompleted()メソッドを呼び出すと、オブザーバーがサブスクライブしているストリームが完了しているかどうかがチェックされます。 assertNoErrors()メソッドは、ストリームのサブスクライブ中にエラーがなかったことをアサートします。
4. 予想される例外のテスト
処理中に、オブザーバブルがイベントを発行しているとき、またはオブザーバーがイベントを処理しているときに、エラーが発生することがあります。 TestSubscriber には、エラー状態を調べるための特別なメソッドがあります。 assertError()メソッドは、例外のタイプを引数として取ります。
List<String> letters = Arrays.asList("A", "B", "C", "D", "E");
TestSubscriber<String> subscriber = new TestSubscriber<>();
Observable<String> observable = Observable
.from(letters)
.zipWith(Observable.range(1, Integer.MAX_VALUE), ((string, index) -> index + "-" + string))
.concatWith(Observable.error(new RuntimeException("error in Observable")));
observable.subscribe(subscriber);
subscriber.assertError(RuntimeException.class);
subscriber.assertNotCompleted();
concatWith()メソッドを使用して、別のオブザーバブルと結合されるオブザーバブルを作成しています。 2番目のオブザーバブルは、次のイベントを発行しているときにRuntimeExceptionをスローします。 assertError()メソッドを呼び出すことにより、TestSubsciberでその例外のタイプを調べることができます。
エラーを受け取ったオブザーバーは処理を停止し、未完了の状態になります。 その状態は、 assertNotCompleted()メソッドで確認できます。
5. 時間ベースのテストObservable
1秒に1つのイベントを発行するObservableがあり、TestSubsciberを使用してその動作をテストするとします。
Observable.interval()メソッドを使用して時間ベースの Observable を定義し、TimeUnitを引数として渡すことができます。
List<String> letters = Arrays.asList("A", "B", "C", "D", "E");
TestScheduler scheduler = new TestScheduler();
TestSubscriber<String> subscriber = new TestSubscriber<>();
Observable<Long> tick = Observable.interval(1, TimeUnit.SECONDS, scheduler);
Observable<String> observable = Observable.from(letters)
.zipWith(tick, (string, index) -> index + "-" + string);
observable.subscribeOn(scheduler)
.subscribe(subscriber);
tick observableは、1秒ごとに新しい値を発行します。
テストの開始時は時間ゼロであるため、TestSubscriberは完了しません。
subscriber.assertNoValues();
subscriber.assertNotCompleted();
テストで通過する時間をエミュレートするには、TestSchedulerクラスを使用する必要があります。 TestSchedulerでadvanceTimeBy()メソッドを呼び出すことにより、その1秒のパスをシミュレートできます。
scheduler.advanceTimeBy(1, TimeUnit.SECONDS);
AdvanceTimeBy()メソッドは、observableが1つのイベントを生成するようにします。 assertValueCount()メソッドを呼び出すことにより、1つのイベントが生成されたと断言できます。
subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValues("0-A");
文字のリストには5つの要素が含まれているため、オブザーバブルですべてのイベントを発行する場合は、6秒の処理が必要です。 その6秒をエミュレートするには、 AdvanceTimeTo()メソッドを使用します。
scheduler.advanceTimeTo(6, TimeUnit.SECONDS);
subscriber.assertCompleted();
subscriber.assertNoErrors();
subscriber.assertValueCount(5);
assertThat(subscriber.getOnNextEvents(), hasItems("0-A", "1-B", "2-C", "3-D", "4-E"));
経過時間をエミュレートした後、TestSubscriberでアサーションを実行できます。 assertValueCount()メソッドを呼び出すことにより、すべてのイベントが生成されたと断言できます。
6. 結論
この記事では、RxJavaでオブザーバブルとオブザーバブルをテストする方法を検討しました。 放出されたイベント、エラー、および時間ベースのオブザーバブルをテストする方法を検討しました。
これらすべての例とコードスニペットの実装は、 GitHubプロジェクトにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。