RxJavaをテストするには?

1概要

この記事では、https://github.com/ReactiveX/RxJava[RxJava]を使用して書かれたコードをテストする方法を検討します。

RxJavaを使って作成する典型的なフローは、 Observable と__Observerで構成されています。observableは、一連の要素であるデータのソースです。 1人以上のオブザーバーが発行されたイベントを受け取るためにそれを購読します。

通常、オブザーバとオブザーバブルは別々のスレッドで非同期的に実行されるため、従来の方法でコードをテストするのは困難です。

幸い、** RxJavaは TestSubscriber クラスを提供します。

2 RxJavaのテスト - 伝統的な方法

  • 例から始めましょう** - 1から始まる整数のシーケンスでzipしたい一連の文字があります。

私たちのテストでは、zip形式のオブザーバブルによって発行されたイベントを監視するサブスクライバが、整数形式のzip形式の文字を受信して​​いることを主張する必要があります。

このようなテストを伝統的な方法で書くことは、結果のリストを保存し、そのリストをオブザーバから更新する必要があることを意味します。整数のリストに要素を追加するということは、観察可能オブジェクトと観察者は同じスレッドで作業する必要があるということです。それらは非同期では機能できません。

したがって、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 インスタンスをオブザーバブルの 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 オブザーバブルは1秒ごとに新しい値を出力します。

テストの開始時には0になっているので、 TestSubscriber は完成しません。

subscriber.assertNoValues();
subscriber.assertNotCompleted();

テストで時間経過をエミュレートするには、 TestScheduler クラスを使用する必要があります。 TestScheduler advanceTimeBy() メソッドを呼び出すことで、1秒間のパスをシミュレートできます。

scheduler.advanceTimeBy(1, TimeUnit.SECONDS);

advanceTimeBy() メソッドは、監視可能オブジェクトにイベントを1つ生成させます。

assertValueCount() メソッドを呼び出すことによって、1つのイベントが生成されたことを表明できます。

subscriber.assertNoErrors();
subscriber.assertValueCount(1);
subscriber.assertValues("0-A");

letters のリストには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でオブザーバとオブザーバブルをテストする方法を調べました。発生したイベント、エラー、および時間ベースの観測量をテストする方法を調べました。

これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/rxjava[GitHubプロジェクト]で見つけることができます - これはMavenプロジェクトです。そのまま実行します。