TIL: Don't mix blockingGet() and Main Looper
RxJava で main thread になんかさせるコードが関与する場合 Observable#blockingFirst() を使うとデッドロックしてしまう。そこで以下のようなかんじで subscription と retrieval を分離し、その間でタスクを flush する。
AtomicReference<String> result = new AtomicReference();
Disposable unused = yourSubject.subscribe(result::set);
shadowOf(getMainLooper()).idle();
assertThat(result.get()).isEqualTo("Expected");
- RxJava のコードには BlockingObsever というのがあるのでこれを使わせてくれれば解決なのだが、使えないので雑に AtomicReference で済ます。
- unit test 内でスレッドのタスクキューを空にする方法は色々あるっぽい。上の例は Robolectric のこの資料をもとにしている。この方法では background threads は待てない。
- Coroutine だとどうするんだろうね?ていうかテストフレームワークがいい加減非同期対応してほしいもんだわ JS とか 10 年前から対応してんだぞ。
追記
Coroutine はサポートがあるらしい。