AndroidでのRxのテスト事始め


先日、[RxAnimation](https://github.com/Reyurnible/RxAnimation)というAndroidのアニメーションのイベントをObservableでラッピングするライブラリを作成しました。
その中で、Rx系のライブラリのテストの書き方に困った時、同じくAndroidのViewをバインディングしているJakeの[RxBinding](https://github.com/JakeWharton/RxBinding)のテストの書き方が参考になったので書きたいと思います。

主に、Rxのテストをするときチェックすのは想定通りのイベントがちゃんと流れてきているかです。
ということは、ストリームから流れてきたイベントを持っておく保持してチェックできれば良さそうですね。
ということで、参考にしたRxBindingのテストを踏まえて簡単に見ていきましょう。

##使用しているライブラリ
テストに使用するライブラリは、基本的に[Android Testing Support Library](https://google.github.io/android-testing-support-library/)
具体的にはここらへん

- [Espresso](https://google.github.io/android-testing-support-library/docs/espresso/index.html)
- [AndroidJUnitRunner](https://google.github.io/android-testing-support-library/docs/androidjunitrunner-guide/index.html)
- [Truth](http://google.github.io/truth/)

##具体的に参考にしたテスト
実際に参考にしたテストはこちら。
RecordingObserverというクラスが、ストリームから受け取ったイベントを保存してくれているみたいです。

```RxViewTest.java
@Test
@UiThreadTest
public void clicks() {
    RecordingObserver<Void> o = new RecordingObserver<>();
    Subscription subscription = RxView.clicks(view).subscribe(o);
    o.assertNoMoreEvents(); // No initial value.

    view.performClick();
    assertThat(o.takeNext()).isNull();

    view.performClick();
    assertThat(o.takeNext()).isNull();

    subscription.unsubscribe();

	view.performClick();
	o.assertNoMoreEvents();
}
```

RxViewのclicksメソッドは、値として[ViewClickOnSubscribe](https://github.com/JakeWharton/RxBinding/blob/master/rxbinding/src/main/java/com/jakewharton/rxbinding/view/ViewClickOnSubscribe.java)を返すようになっていて、ViewClickOnSubscribeの中身はこのような形でViewがクリックされると、onNextを呼ぶという代物です。


##RecordingObserver
今回参考にしたRecordingObserverは、RxBindingのリポジトリの中に[testing-utils](https://github.com/JakeWharton/RxBinding/tree/master/testing-utils)というmoduleとして入っています。
RecordingObserverの中身はこのような形で、

```RecordingObserver.java
public final class RecordingObserver<T> implements Observer<T> {
  private static final String TAG = "RecordingObserver";

  private final BlockingDeque<Object> events = new LinkedBlockingDeque<>();

  @Override public void onCompleted() {
    Log.v(TAG, "onCompleted");
    events.addLast(new OnCompleted());
  }

  @Override public void onError(Throwable e) {
    Log.v(TAG, "onError", e);
    events.addLast(new OnError(e));
  }

  @Override public void onNext(T t) {
    Log.v(TAG, "onNext " + t);
    events.addLast(new OnNext(t));
  }

  private <E> E takeEvent(Class<E> wanted) {
    Object event;
    try {
      event = events.pollFirst(1, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    if (event == null) {
      throw new NoSuchElementException(
          "No event found while waiting for " + wanted.getSimpleName());
    }
    assertThat(event).isInstanceOf(wanted);
    return wanted.cast(event);
  }

  public T takeNext() {
    OnNext event = takeEvent(OnNext.class);
    return event.value;
  }

  public Throwable takeError() {
    return takeEvent(OnError.class).throwable;
  }

  public void assertOnCompleted() {
    takeEvent(OnCompleted.class);
  }

  public void assertNoMoreEvents() {
    try {
      Object event = takeEvent(Object.class);
      throw new IllegalStateException("Expected no more events but got " + event);
    } catch (NoSuchElementException ignored) {
    }
  }

  private final class OnNext {
    final T value;

    private OnNext(T value) {
      this.value = value;
    }

    @Override public String toString() {
      return "OnNext[" + value + "]";
    }
  }

  private final class OnCompleted {
    @Override public String toString() {
      return "OnCompleted";
    }
  }

  private final class OnError {
    private final Throwable throwable;

    private OnError(Throwable throwable) {
      this.throwable = throwable;
    }

    @Override public String toString() {
      return "OnError[" + throwable + "]";
    }
  }
}
```

各イベントクラス

- OnNext.class
- OnError.class
- OnComplete.class

で受け取ったものを、Dequeにためています。
そのため、onNextが呼ばれたかをチェックするには、

```RecordingObserver.java
assertThat(o.takeNext()).isNull();
```

onErrorが呼ばれたかをチェックするには、


```RecordingObserver.java
assertThat(o.takeError()).isNull();
```

onCompleteが呼ばれたかをチェックするには、

```RecordingObserver.java
o.assertOnCompleted();
```

これ以上イベントがDequeに溜まっていないかをチェックするには、

```RecordingObserver.java
o. assertNoMoreEvents();
```

を実行すればよいみたいです。

##おわりに
あまり身のない内容だったかもしれないですが、Rxのテストは戸惑いが多かったので、頭の整理も含め書いてみました。
Rxもテストもまだまだ初心者ですので、何かもっとよい知見があれば教えていただきたいです！