Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RxJavaの非同期処理に負けないEspressoテストコードを書く / Let's Write Espresso Tests Synchronizing with RxJava's Asynchronous Processing

RxJavaの非同期処理に負けないEspressoテストコードを書く / Let's Write Espresso Tests Synchronizing with RxJava's Asynchronous Processing

Rx Ja Night Vol.2
で発表予定の「RxJavaの非同期処理に負けないEspressoテストコードを書く」の発表資料です。

サンプルコードは
https://github.com/sumio/RxJavaEspressoSample
で公開しています。

TOYAMA Sumio

June 12, 2017
Tweet

More Decks by TOYAMA Sumio

Other Decks in Programming

Transcript

  1. ⾃⼰紹介 p ⽒名: 外⼭ 純⽣ (TOYAMA Sumio) @sumio_tym (Twitter) /

    @sumio (GitHub) p 所属: NTTテクノクロス株式会社 p 業務内容: p 社内Androidプロジェクトの技術⽀援 p 社内Androidプロジェクトのテスト⾃動化⽀援 p プライベート: p STAR(テスト⾃動化研究会) p @IT連載「スマホ向け無料システムテスト⾃動化 ツール」(UI Automator / Appiumの回を担当) 2
  2. Espressoの⾮同期処理待ち合わせ AsyncTask以外の⾮同期処理待ち合わせ p 独⾃IdlingResourceを実装すればOK 6 public interface IdlingResource { public

    String getName(); public boolean isIdleNow(); public void registerIdleTransitionCallback( ResourceCallback callback); } 「今アイドル状態ですか?」 という質問に答えるように実装する
  3. 使うもの (RxJava1) RxJavaHooksクラス p setOnScheduleAction(Func1<Action0, Action0>) タスクがスケジューリングされる直前に呼び出される フックを設定する 9 //

    ログを仕込む例 RxJavaHooks.setOnScheduleAction(oldAction -> { Log.d(TAG, "スケジューリングされた"); return () -> { Log.d(TAG, "実⾏直前"); oldAction.call(); }; });
  4. 使うもの (RxJava2) RxJavaPluginsクラス p setScheduleHandler(Function<? super Runnable, ? extends Runnable>)

    タスクがスケジューリングされる直前に呼び出される フックを設定する 10 // ログを仕込む例 RxJavaPlugins.setScheduleHandler(oldAction ->{ Log.d(TAG, "スケジューリングされた"); return () -> { Log.d(TAG, "実⾏直前"); oldAction.run(); }; });
  5. 解決⽅針 setOnSchedulerAction / setScheduleHandler (以降スケジューリングフックと呼びます) で、以下の処理を差し込む 1. 実⾏直前にCountingIdlingResourceを インクリメントする 2.

    実⾏直後にCountingIldingResourceを デクリメントする 何も実⾏されていないとき ‖ カウント0の「アイドル状態」 11
  6. 解決コード (RxJava1) 12 private CountingIdlingResource ires; @Before public void setUp()

    { ires = new CountingIdlingResource("RxJava"); RxJavaHooks .setOnScheduleAction(oldAction -> () -> { try { ires.increment(); oldAction.call(); } finally { ires.decrement(); }}); Espresso.registerIdlingResources(ires); } @After public void tearDown() { Espresso.unregisterIdlingResources(ires); RxJavaHooks.reset(); }
  7. 解決コード (RxJava2) 13 private CountingIdlingResource ires; @Before public void setUp()

    { ires = new CountingIdlingResource("RxJava"); RxJavaPlugins .setScheduleHandler(oldAction -> () -> { try { ires.increment(); oldAction.run(); } finally { ires.decrement(); }}); Espresso.registerIdlingResources(ires); } @After public void tearDown() { Espresso.unregisterIdlingResources(ires); RxJavaHooks.reset(); }
  8. 解決コード (RxJava2) 14 private CountingIdlingResource ires; @Before public void setUp()

    { ires = new CountingIdlingResource("RxJava"); RxJavaPlugins .setScheduleHandler(oldAction -> () -> { try { ires.increment(); oldAction.run(); } finally { ires.decrement(); }}); Espresso.registerIdlingResources(ires); } @After public void tearDown() { Espresso.unregisterIdlingResources(ires); RxJavaHooks.reset(); }
  9. 注意: フック設定タイミング RxJavaの⾮同期タスクが無い状態でフッ クを設定する必要がある 15 // Activity起動時に⾮同期処理が⾛る場合は // フック設定後にActivityを起動するようにする @Rule

    public ActivityTestRule<MyActivity> activityRule = new ActivityTestRule<>(MyActivity.class, false, false); @Before public void setUp() { ... // (省略)スケジューラーフックを設定する Espresso.registerIdlingResources(ires); activityRule.launchActivity(null); }
  10. 限界①: 遅延スケジューリング 実⾏状態以外のタスクがあっても 「アイドル状態」とみなされてしまう 16 // ボタンを押してから3秒間放置するとテキストを表⽰する例 RxView.clicks(button) .debounce(3, TimeUnits.SECONDS)

    .subscribe(v -> textView.setText("OK")); 3秒待ってる間は 「アイドル状態」 「ボタンを押したらOKと表⽰されること」 というテストは失敗してしまう
  11. 限界②を回避する 設定済みのフックを更にフックする p テスト実⾏中にアプリ側で再設定されないならOK 19 // RxJava1の例 Func1<Action0, Action0> oldOnScheduleAction

    = RxJavaHooks.getOnScheduleAction(); RxJavaHooks.setOnScheduleAction(oldAction -> () -> { try { ires.increment(); oldOnScheduleAction .call(oldAction).call(); } finally { ires.decrement(); } });
  12. 参考URL ① RxAndroidのIssue #149 (様々な解決⽅法が議論されている) https://github.com/ReactiveX/RxAndroid/issues/149 ② Iñaki Villar「Espresso: Beyond

    the Basics」(Mobilization 2016) (本トークとほぼ同じ⽅法を紹介) https://goo.gl/AiQ2uJ ③ Joshua Kovach「Retrofitting Espresso」 (RxのスケジューラをAsyncTaskに差し替える ⽅法を紹介) https://goo.gl/2p3E6S 21