cookpad.apk#4

024ce2681fa10ce9c1d8aa707d376d72?s=47 ksfee684
February 13, 2020

 cookpad.apk#4

024ce2681fa10ce9c1d8aa707d376d72?s=128

ksfee684

February 13, 2020
Tweet

Transcript

  1. Shared Test を実装する上で 気をつけなければいけないこと Cookpad.apk #4

  2. 自己紹介 • 加藤 恭平(@ksfee684) • モバイル基盤部所属 • Android アプリプロジェクトの開発効率化、基盤技術開発

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

    • テスト実行環境の選択 • Shared Test とは • Shared Test を実装する上で気をつけること
  4. 今日伝えたいこと DroidKaigi で sumio_tym さんの 「Robolectric の限界を理解して UI テストを高速に実行しよう」をぜひ御覧ください

  5. Android におけるテスト

  6. https://developer.android.com/training/testing/fundamentals#testing-pyramid

  7. テスト実行環境 • 実機端末 or エミュレータ ◦ Instrumentation Test ◦ テストをパッケージングして端末上で実行

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

    ◦ Handler, Looper, UI(View レンダリング) • ローカル JVM では以下のようなものがうまく動かない ◦ イベントループ ◦ ライフサイクルイベント • ローカル JVM でもテストを実行したい
  9. そこで Robolectric • Android API を利用するテストをローカル JVM で動作させるすごいやつ ◦ なぜかエミュレータを使わなくてもテストが動作する

    ◦ なぜかローカル JVM で動作する ◦ なぜか普通の JUnit テストより遅い
  10. Robolectric は どのように機能するか

  11. Android の OS の挙動を模倣している

  12. None
  13. 動かない部分はごまかす(Shadow) • 実際には実現できない部分、普通のローカル JVM でテストを実行する上で工夫しなければ 行けない部分を Shadow として実装 • ほとんどのオブジェクトは

    Android API(SDK)の実装をベースとして一部のメソッドだけ置き 換えている
  14. ローカル JVM で Android API を利用できるようになったので Activity や Fragment のテストもすべて

    Robolectric で完璧!!
  15. すべてのテストを Robolectric で書けば良い? • そんな夢みたいな話はない • OS の挙動をあくまで模倣しているだけなので実際の動きとは異なるものになっている • では具体的にはどういった点が違うのか

  16. Robolectric で できること/できないこと

  17. できること • 結構いろいろできる ◦ ライフサイクルメソッドの呼び出し ▪ ActivityScenario, FragmentScenario ▪ onCreate,

    onActivityResult ◦ Context およびリソースへのアクセス ◦ Espresso を用いた UI テスト ▪ View へのアクセス
  18. 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)))
  19. できないこと • Shadow で実装されたメソッドで大きく Android 実行環境と異なる箇所がいくつか存在する ◦ Looper のイベントループ ◦

    Activity 及び ActivityManager の状態管理 ◦ View レンダリング
  20. 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
  21. 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();
  22. 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();
  23. 詳しくは… より Robolectric の詳しい内容は sumio_tym さんの 「Robolectric の限界を理解して UI テストを高速に実行しよう」をおすすめします

  24. テスト実行環境の選択

  25. Android 実行環境でのテスト実行がボトルネックに • Android 実行環境構築のコスト ◦ CI 環境の構築 • 実行のコスト

    ◦ ビルド -> パッケージング -> インストール -> 実行 • とはいえ Robolectric で置き換えが可能か判断しにくいものもある
  26. Shared Test とは

  27. テスト実行タイミングによって実行環境を変える • Robolectric と Android 実行環境どちらでも動作するようにテストを実装する ◦ 実行頻度の高いタイミングでは Robolectric での実行結果で判断する

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

    ◦ 実装をする上で考慮しなければならない事項を減らす • UI テストの実行コストを減らしたい ◦ テストごとに何を検証しているかを考える ◦ ライフサイクル、非同期タスクの処理の順序等を考慮しなければならない場合はさける • 実際のサンプルとかは? ◦ CodeLab から消えている…
  30. クックパッドでは? • 現在のところクックパッドアプリでは Shared Test はありません! ◦ 一部リソース(TestApplication 等)を共有するだけに留まっている ◦

    今後テスト実行コストを評価した際に検討するかも …?
  31. まとめ • Android アプリにおける Robolectric の働き • タイミングによって実行環境が変わる Shared Test

    • Shared Test の実装目安