アプリのE2Eテストするとき、通信が完了するまで待つ必要がある。たとえば、E2Eテストにログイン操作があるとき。通信を待たないとログインの通信中にログイン後の画面を検証したり操作したりするので、当然テストは失敗する。
通信などの非同期処理をRxで実行しているとき、テストを待機させる方法を記述する。Androidアプリ、Espressoで使っているときの話。
実現手順
基本的な考え方
- IdlingResourceを使う
- プロダクトコード内のRxの非同期処理1つ1つにIdlingResourceを使った処理は仕込まない
RxJavaPlugins#setScheduleHandlerを使うと実現できる。Rxの全非同期処理の実行前後に、独自の処理を仕込めるので、それを利用する。
Step0. IdlingResourceの導入
大体Espresso入れるときに、セットで導入しているとは思うが、一応示しておく。
app/build.gradle
dependencies {
// ここではプロダクトコードでIdlingResourceを使わないので、androidTestImplementation
androidTestImplementation "androidx.test.espresso:espresso-idling-resource:3.3.0"
}
Step1. CountingIdlingResourceで実行中の非同期処理をカウントする
汎用性のある処理なのでJUnitのTestRuleとして実装する。
RxTestRule
class RxTestRule : TestRule {
override fun apply(base: Statement?, description: Description?): Statement = object : Statement() {
override fun evaluate() {
val rxIdlingResource = CountingIdlingResource("RxJava2", true)
RxJavaPlugins.setScheduleHandler { oldAction ->
Runnable {
try {
rxIdlingResource.increment() // 非同期処理が開始前にカウントアップ
oldAction.run()
} finally {
rxIdlingResource.decrement() // 非同期処理が開始前にカウントダウン
}
}
}
val registry = IdlingRegistry.getInstance()
registry.register(rxIdlingResource) // EspressoにCountingIdlingResourceを監視させる
try {
base?.evaluate()
} finally {
registry.unregister(rxIdlingResource) // テスト終わったらCountingIdlingResourceの監視を解除する
}
}
}
}
※evaluateの中で@Before, @Test, @Afterの処理が実行される。
Step2. Rxの非同期処理の実行数が1以上の間、EspressoのAPIが待機するようにする
先程作ったTestRuleをUIテストを実行するクラスに適用する。
@LargeTest
@RunWith(AndroidJUnit4::class)
class FooTests {
@get:Rule
val rxTestRule = RxTestRule()
...
}
これで少なくともRxの非同期処理の実行数が1以上の間は、sleepなしでEspressoのAPIが待機してくれるようになる。