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

cookpad.apk#4

Kyohei Kato
February 13, 2020

 cookpad.apk#4

Kyohei Kato

February 13, 2020
Tweet

More Decks by Kyohei Kato

Other Decks in Programming

Transcript

  1. アジェンダ • Android におけるテスト • Robolectric はどのように機能するか • Robolectric でできること/できないこと

    • テスト実行環境の選択 • Shared Test とは • Shared Test を実装する上で気をつけること
  2. テスト実行環境 • 実機端末 or エミュレータ ◦ Instrumentation Test ◦ テストをパッケージングして端末上で実行

    ◦ 実行時間が長い ◦ 複雑でメンテナンスコストが高く、デバッグが難しい • ローカル JVM ◦ クラス単位での Unit テスト ◦ Android API を利用するテストがほぼ実行不可能 ◦ 実行時間が短い ◦ シンプルかつデバッグも比較的容易
  3. なぜローカル JVM で Android API を利用できないのか • クラス単体では OS の機能をベースとした動作を確認できない

    ◦ Handler, Looper, UI(View レンダリング) • ローカル JVM では以下のようなものがうまく動かない ◦ イベントループ ◦ ライフサイクルイベント • ローカル JVM でもテストを実行したい
  4. できること • 結構いろいろできる ◦ ライフサイクルメソッドの呼び出し ▪ ActivityScenario, FragmentScenario ▪ onCreate,

    onActivityResult ◦ Context およびリソースへのアクセス ◦ Espresso を用いた UI テスト ▪ View へのアクセス
  5. http://robolectric.org/androidx_test/ // GIVEN val contactName = "Test User" val scenario

    = launchActivity<AddContactActivity>() // WHEN // Enter contact name onView(withId(R.id.contact_name_text)).perform(typeText(contactName)) // Destroy and recreate Activity scenario.recreate() // THEN // Check contact name was preserved. onView(withId(R.id.contact_name_text)).check(matches(withText(contactName)))
  6. Looper • 元々 Looper にポストされたタスクを同期的に実行する実装だった • v4.3 からは PausedLooper という仕組みが入り、

    Queue に一時的にタスクをため、任意のタイミング で execute が可能となった • 参考 ◦ http://robolectric.org/blog/2019/06/04/paused-looper/ ◦ https://github.com/robolectric/robolectric/blob/master/robolectric/src/test/java/org/robolectric/shadows/ShadowLega cyLooperTest.java ◦ https://github.com/robolectric/robolectric/blob/master/robolectric/src/test/java/org/robolectric/shadows/ShadowPaus edLooperTest.java
  7. http://robolectric.org/blog/2019/06/04/paused-looper/ List<String> events = new ArrayList<>(); events.add("before"); new Handler(Looper.getMainLooper()).post(() ->

    events.add("after")); events.add("between"); assertThat(events).containsExactly("before", "between", "after").inOrder();
  8. http://robolectric.org/blog/2019/06/04/paused-looper/ List<String> events = new ArrayList<>(); events.add("before"); new Handler(Looper.getMainLooper()).post(() ->

    events.add("after")); events.add("between"); // the 'after' task is posted, but has not been executed yet assertThat(events).containsExactly("before", "between").inOrder(); // execute all tasks posted to main looper shadowOf(getMainLooper()).idle(); assertThat(events).containsExactly("before", "between", "after").inOrder();
  9. Android 実行環境でのテスト実行がボトルネックに • Android 実行環境構築のコスト ◦ CI 環境の構築 • 実行のコスト

    ◦ ビルド -> パッケージング -> インストール -> 実行 • とはいえ Robolectric で置き換えが可能か判断しにくいものもある
  10. テスト実行タイミングによって実行環境を変える • Robolectric と Android 実行環境どちらでも動作するようにテストを実装する ◦ 実行頻度の高いタイミングでは Robolectric での実行結果で判断する

    ◦ クリティカルなタイミングでは Android 実行環境化でテストを実行することでテスト結 果を判断する • 日々の開発におけるテストの実行速度を高速化する ◦ どちらの実行環境でも実行されるテスト -> Shared Test
  11. Shared Test を実装する上で気をつけること • Robolectric が理解できていないうちはすべて Android 実行環境上で動作させるべき ◦ 下手にバグを踏まない

    ◦ 実装をする上で考慮しなければならない事項を減らす • UI テストの実行コストを減らしたい ◦ テストごとに何を検証しているかを考える ◦ ライフサイクル、非同期タスクの処理の順序等を考慮しなければならない場合はさける • 実際のサンプルとかは? ◦ CodeLab から消えている…