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

Android スクリーンショットテスト 3つのプロダクトに導入する中で倒してきた課題【DeN...

DeNA_Tech
March 03, 2021

Android スクリーンショットテスト 3つのプロダクトに導入する中で倒してきた課題【DeNA TechCon 2021】/techcon2021-16

Androidアプリ開発において、UI周りの不具合はつきものです。そうしたUIに関する問題の早期発見を目的として、3つのプロダクトにスクリーンショットを活用した自動テスト(スクリーンショットテスト)を導入しました。

ひとえにスクリーンショットテストの導入といっても、プロダクトによって導入までの課題は様々です。例えば、依存の差し替えをどのようにしたらいいか、画面の待ち合わせをどのようにしたらいいかといった課題はプロダクトごとに検討する必要がありました。加えて、意図した通りのスクリーンショットを安定して取るにはどうしたらいいか、といったスクリーンショットテスト特有の課題もありました。

本セッションでは、3つのプロダクトにスクリーンショットテスト導入する中で直面した課題と、それらをどのように解決したかを紹介します。また、新たにスクリーンショットテストを導入する際に気をつけるべきことについても解説します。

DeNA_Tech

March 03, 2021
Tweet

More Decks by DeNA_Tech

Other Decks in Technology

Transcript

  1. • 田熊 希羽(タクマ ノゾミ) • 品質管理部 SWETグループ所属 ◦ Pocochaシステム部兼務 ◦

    株式会社Mobility Technologies兼務出向 • Androidとテストが好き 4
  2. 21

  3. @Test fun capture() { // 画面起動前にテストデータのセットアップを行う // テストしたい画面の起動 val intent

    = Intent(context, RankingActivity::class.java) val scenario = launchActivity<RankingActivity>(intent ) scenario.onActivity activity // スクリーンショットを取得・保存 } } 23
  4. @Test fun capture() { // 画面起動前にテストデータのセットアップを行う // テストしたい画面の起動 val intent

    = Intent(context, RankingActivity::class.java) val scenario = launchActivity<RankingActivity>(intent ) scenario.onActivity activity // スクリーンショットを取得・保存 } } ActivityScenarioといった テスト用の画面起動APIが用意されている 24
  5. @Test fun capture() { // 画面起動前にテストデータのセットアップを行う // テストしたい画面の起動 val intent

    = Intent(context, RankingActivity::class.java) val scenario = launchActivity<RankingActivity>(intent ) scenario.onActivity activity // スクリーンショットを取得・保存 } } 実機やEmulatorを使った Instrumentation Testとして 実行する 25
  6. • GO ◦ タクシー配車サービス • 乗務員アプリ ◦ GOのタクシー乗務員が利用するアプリ • Pococha

    ◦ ライブコミュニケーションサービス 実際に運用するのが難しくなり断念 27
  7. • GO ◦ タクシー配車サービス • 乗務員アプリ ◦ GOのタクシー乗務員が利用するアプリ • Pococha

    ◦ ライブコミュニケーションサービス うまくいかなかったプロダク トもあわせて、直面した様々 な課題を紹介していきます 28
  8. 意図した通りのスクリーン ショットを取得する 安定したスクリーンショット を取得する スクリーンショットテストを 定着させる • 依存の差し替えをどうするか • テストの結合範囲をどうするか

    • モックライブラリMockkの罠 • Applicationクラスの障壁 • 画面起動のパターンに対応する テストしたい画面を任意の状 態で起動できるようにする 32
  9. 37

  10. 38

  11. • バイトコードに処理を差し込むことで機能を実現 ◦ Mock final and static methods on Android

    devices • Androidの実機で動作させるとランダムにクラッ シュする上、クラッシュのログがでない • Andorid11ではinline mock機能を使わない場合 でも、inline mockのセットアップでクラッシュ 45
  12. val activityScenario = launchActivity<MyActivity>(intent) activityScenario.onActivity { act : MyActivity ->

    val navController = Navigation.findNavController(act, R.id.nav) navController.navigate(..) } 起動したActivityのインスタンスからpublicアクセス できるものはテストコードからもアクセス可能 54
  13. 意図した通りのスクリーン ショットを取得する 安定したスクリーンショット を取得する スクリーンショットテストを 定着させる • 依存の差し替えをどうするか • テストの結合範囲をどうするか

    • モックライブラリMockkの罠 • Applicationクラスの障壁 • 画面起動のパターンに対応する テストしたい画面を任意の状 態で起動できるようにする 55
  14. • スクロールをしながらスクリーンショットを取得 ◦ スクリーンショット → スクロール → スク リーンショット... •

    全体をスクリーンショットできるように画面をリ サイズしたあとスクリーンショットを撮る 66
  15. • 開発者オプションのシステムUIデモモード ◦ Demo Mode for the Android System UI

    • テストコードから有効化するには(値は↑を参照) ◦ UiAutomation#executeShellCommandで adbを実行し、デモモードを有効化 ◦ 必要なコマンドをBroadcastで発行 73
  16. 意図した通りのスクリーン ショットを取得する 安定したスクリーンショット を取得する スクリーンショットテストを 定着させる • 依存の差し替えができるか • アーキテクチャにあわせて結合

    範囲を検討する • モックライブラリ利用の可否 • Applicationクラスにテストの 邪魔になりそうな処理はないか • アプリの画面構成とどのような 起動経路があるかを確認する テストしたい画面を任意の状 態で起動できるようにする 88
  17. スクリーンショットテストを 定着させる 意図した通りのスクリーン ショットを取得する 安定したスクリーンショット を取得する • 利用している非同期処理の機構 にあわせて待ち合わせの仕組み を実装する

    • 画面の特性にあわせて、スク リーンショットAPIを選択する • FragmentScenarioの代替手段 を用意する • スクロールする画面の対応方針 を決めて仕組みを実装する テストしたい画面を任意の状 態で起動できるようにする 89
  18. 95