Slide 1

Slide 1 text

ⓒ 2020 DeNA Co., Ltd. 2020/02/20 システム本部 品質統括部 品質管理部 SWETグループ DeNA Co., Ltd. 1 DroidKaigi 2020ハンズオン
 EspressoではじめるAndroid UIテスト

Slide 2

Slide 2 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 講師紹介 2 ● 氏名: 田熊 希羽 (Nozomi Takuma) @fgfgtkm (Twitter) / @tkmnzm (GitHub) ● 所属: DeNA SWETグループ (Software Engineer in Test) ● Androidアプリ開発のテスタビリティ改善・テスト自動 化支援 ● 本日13:00~「自動生成でさくさく実装するユニットテス ト」というタイトルで発表しました

Slide 3

Slide 3 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 講師紹介 ● 氏名: 外山 純生 (TOYAMA Sumio) @sumio_tym (Twitter) / @sumio (GitHub) ● 所属: DeNA SWETグループ (Software Engineer in Test) ● 業務内容: − Androidアプリ開発 テスト自動化支援 ● その他: − 「Androidテスト全書」執筆 − 明日17:00~「Robolectricの限界を理解してUIテストを高 速に実行しよう」@Pickersで登壇します! 3

Slide 4

Slide 4 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. この資料について 本資料は、関係者の許諾の元で 書籍「Androidテスト全書」の「4章 UIテスト(概要編)」 の内容を一部流用して作成しています。 「Androidテスト全書」にはここで紹介する内容のほか、 役立つ情報が満載です。 気になる方は読んでみてください! https://peaks.cc/android_testing 4

Slide 5

Slide 5 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 本ハンズオンの目標 ● UIテストの特徴を理解する ● UIテストを書き始める足がかりとして 次のAPIを理解する (DeNA Codelabs) − Activity・Fragmentを起動するAPI − Espressoの基本的なAPI − RecyclerView操作のAPI (自習) − 画面更新を待ち合わせるAPI (自習) 5

Slide 6

Slide 6 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 本資料の構成 本日のハンズオンでは一部割愛します 1. UIテストの自動化を始める前に 2. テストツール選択のポイント 3. 長くテストコードを利用し続けるには 4. Espresso APIを使いこなしてUIテストを書いて みよう(DeNA Codelabs) 6

Slide 7

Slide 7 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 7 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 8

Slide 8 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 8 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 9

Slide 9 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-1. UIテストの特徴① ユニットテスト vs UIテスト 9 This image is reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

Slide 10

Slide 10 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-1. UIテストの特徴① ユニットテスト vs UIテスト 10 This image is reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License. UIテストはユニットテストに比べて・・ ● より実環境に近い(Fidelityが高い) ● 実行時間が長い ● メンテナンスコストが高い ● デバッグコストが高い

Slide 11

Slide 11 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-1. UIテストの特徴② (参考) UIテストの分類 11 忠実度 実行時間 分類 高 遅い E2E Test 中 普通 Instrumented Test 低 速い Local Test (Robolectric)

Slide 12

Slide 12 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-1. UIテストの特徴③ ● 画面デザインが変更されると、テストコードも修 正しなければならない ● UIに起因する理由でテストが安定しない − UI操作→画面変化までの時間がまちまち − 操作を中断するダイアログが突然表示されるかも − ログイン画面 − パーミッションダイアログ 12 無計画に自動化すると 運用コストの増加に耐えられなくなることに!

Slide 13

Slide 13 text

13 せっかく自動化したUIテストの運用を 諦めてしまわないために・・・ きちんと計画をたてましょう。 ● 目的を整理する ● 自動化する範囲を決める ● テストツールを選択する ● スケジュール・予算・体制を決める

Slide 14

Slide 14 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 14 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 15

Slide 15 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-2. 目的を整理する① テスト自動化の利害関係者は意外とたくさん ● プロダクトオーナー ● QAチーム ● 開発チーム ● etc. 15 UIテスト自動化への期待は人それぞれ!

Slide 16

Slide 16 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-2. 目的を整理する② ● テスト担当者への精神的負担の軽減 「退屈な(MPを消費する)テストから解放されたい」 ● 開発コストの削減 「リリースまでのリードタイム短縮したい」 ● 既存機能のバグを予防 「思わぬバグを入れてしまう不安から解放されたい」 16 UIテスト自動化への期待を関係者で議論する 「検証コストの削減」以外にも・・・

Slide 17

Slide 17 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-2. 目的を整理する③ 条件を追加すると達成しやすい ● 検証コスト削減 + 精神的負担の軽減 ● 検証コスト削減 + 既存機能のバグを予防 17 UIテスト自動化で一番難しいこと ● 自動化にかかる投資を 検証コストの減少だけで回収すること 意思決定者と合意しておくのを忘れない!

Slide 18

Slide 18 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 18 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 19

Slide 19 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-3. 自動化する範囲を決める① ● 自動化できるものは全て自動化する ● 目的から逸れた箇所を自動化して満足してし まう 19 自動化の範囲をむやみに広げると メンテナンスコストが上がってしまう! UIテスト自動化のアンチパターン

Slide 20

Slide 20 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-3. 自動化する範囲を決める② 1. 手動・自動関係なく、どのような切り口でテスト をするか整理する 2. 目的を達成できる自動化候補を選ぶ − 検証コスト削減が目的なら・・・ 何度も行うテスト・時間がかかるテスト − QAの精神的負担軽減が目的なら・・・ 担当者が辛いと思っているテスト 20

Slide 21

Slide 21 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-3. 自動化する範囲を決める③ 3. 自動化候補に優先度をつける − 自動化が容易なものを優先する 採用するテストツールによっても変化する − 変更可能性が少ない画面を優先する − 自動操作する画面数が少なくなるようにする 自動操作するUIコンポーネント数が増えると辛い (テスト書く工数が増える) 4. 予算内に収まるように自動化する範囲を決める 21

Slide 22

Slide 22 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 22 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 23

Slide 23 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-4. テストツール(*)を選択する① 次の観点でテストツールを選ぶ ● 自動化したい内容が簡単に実現できるか − トラブル無く、安定してテスト実行できるか ● 低コストで学習できるか − 担当者にとって書きやすいか − 近くに質問できる人がいるか ● 開発コミュニティは活発か − 今後も開発が続きそうか? − 情報が充実しているか? 23 (*) ここではUIテスト自動化を実現するツールのことを指す

Slide 24

Slide 24 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-4. テストツールを選択する② 自動化が不可能・困難なものは どのツールを選択しても無理なことに注意 ● 端末に対する物理的な操作 − 端末を傾ける、振る、など ● Viewと無関係な場所の操作 − 指で文字を描く、など 24

Slide 25

Slide 25 text

ⓒ 2020 DeNA Co., Ltd. 1. UIテストの自動化を始める前に 25 1. UIテストの特徴 2. 目的を整理する 3. 自動化する範囲を決める 4. テストツールを選択する 5. スケジュール・予算・体制を決める

Slide 26

Slide 26 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5. スケジュール・予算・体制を決める それぞれポイントに絞って紹介します 1. スケジュール − とにかくスモールスタートで始める − リリース優先度を考慮したスケジュールにする 2. 予算 − ROIを意識する − 目標を決めておく 3. 体制 − テスト自動化担当者を確保する 26

Slide 27

Slide 27 text

ⓒ 2020 DeNA Co., Ltd. 1-5-1. スケジュール検討のポイント 27

Slide 28

Slide 28 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-1. スケジュール検討のポイント① とにかくスモールスタートで始めよう ● UIテストでは運用フェーズで直面する課題が多い ● 運用期間をできるだけ長く確保するのが大事 ❌ 全部作ってからCIで運用を開始! 一つだけ作ったらCIで運用を開始! 28

Slide 29

Slide 29 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-1. スケジュール検討のポイント② リリース優先度を考慮したスケジュールにしよう (新機能のテストを自動化する場合) ● リリース優先度が高いテストから自動化する ● 自動化が間に合わなければQAに検証依頼 ● 自動テストの結果レポートを元にリリース内容を調整 29

Slide 30

Slide 30 text

ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント 30

Slide 31

Slide 31 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント① ROI (Return On Investment)を意識する ● 自動化にかけたコストに対する利益の割合 ● 1を超えれば投資を回収できたことになる ● 自動テストを繰り返すとROIが増えることが多い 31 テスト自動化の利益 テスト自動化の初期コスト + テスト自動化後の運用コスト ROI =

Slide 32

Slide 32 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント② ROIの計算: 自動化にかかるコスト (: 時間の経過ともに増えていくもの) ● 初期コスト − テストツールの学習コスト − テストを書くコスト ● 運用コスト − テスト結果レポートの解析・原因切り分けコスト − プロダクト仕様変更にともなうテスト修正コスト 32

Slide 33

Slide 33 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント③ ROIの計算: テスト自動化の利益 以下の項目の和を計算する 33 ➕/ ➖ 項目 ➕ 手動のままテストを続けたときの運用コスト ➖ 自動化にかかる初期コスト ➖ テストを自動化した後の運用コスト

Slide 34

Slide 34 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント④ ROIの定義をもう一度 34 テスト自動化の利益 テスト自動化の初期コスト + テスト自動化後の運用コスト ROI = ● 通常は テスト自動化の利益>テスト自動化後の運用コスト ● 運用が長くなると(自動テストを繰り返すと) ROIが1を超えることが多い

Slide 35

Slide 35 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント⑤ 目標を決めておく ● 改善策の検討や継続可否の判断のために必要 − ROIが1を超える(損益分岐点に達する)時期 (それまでに必要な自動テスト実施回数) − 検証コスト削減以外が目的の場合は・・・ どれだけコストをかけ続けられるか 35

Slide 36

Slide 36 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント⑥ 目標を決めたいけど見積もりが難しいとき ● 初期開発コストは頑張って見積もる − 1ケースだけ作成し、その実績を元に見積もる − 過去の事例を参考にする − 経験者に聞く ● 自動化の運用コストはざっくり決める (例: 2人時/週) − 後から精度を上げていけばOK 36

Slide 37

Slide 37 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-2. 予算検討のポイント⑦ 目標の達成度を知るために 運用時に作業時間を記録すること! ● ROIを計算するために必要 ● 記録しないと、自動化が成功しているかどうか判断で きなくなるので重要! 37

Slide 38

Slide 38 text

ⓒ 2020 DeNA Co., Ltd. 1-5-3. 体制検討のポイント 38

Slide 39

Slide 39 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 1-5-3. 体制検討のポイント テスト自動化担当者を確保する ● 専任のテスト自動化担当者を設けるのは難しい − テストを自動化できる=ソフトウェアを開発できる − プロダクトの開発で忙しいことが多い ● 兼任の場合は、以下を必ず確保する − 自動化に必要な学習・実装の時間 − 有識者に相談できるルート (片手間で自動化するのは無理) 39

Slide 40

Slide 40 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ここまでのまとめ ● 関係者でUIテストの目的を決めましょう − 検証コスト削減以外の目的もあり ● 目的を達成できるように以下を決めていく − 自動化する範囲 − 目的の範囲内で容易に実現できるものを優先 − 採用するテストツール − スケジュール・予算・体制 − スモールスタートで早く運用に入る − ROIを意識する − 自動化のための時間を確保できる体制にする 40

Slide 41

Slide 41 text

ⓒ 2020 DeNA Co., Ltd. 2. テストツール選択のポイント 41 1. EspressoとAppiumの概要 2. EspressoとAppiumの比較

Slide 42

Slide 42 text

ⓒ 2020 DeNA Co., Ltd. 2. テストツール選択のポイント 42 1. EspressoとAppiumの概要 2. EspressoとAppiumの比較

Slide 43

Slide 43 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-1. EspressoとAppiumの概要① Espresso ● AndroidX Testの一部として公式に提供 ● 実機・エミュレータで動くInstrumented Test (Robolectricでも動くようになってきた) ● APIレベル19以上であれば、 UI Automatorと併用して他アプリの操作も可能 43

Slide 44

Slide 44 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-1. EspressoとAppiumの概要② Appium ● 3rd party OSS(開発: JS Foundation) ● リリース版apkをそのままテストできる (E2E Testに向いている) ● Selenium WebDriverと同様なAPIで Androidアプリをテストする ● クライアント/サーバアーキテクチャ ● 内部はEspressoやUI Automatorを使って実現 44

Slide 45

Slide 45 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-1. EspressoとAppiumの概要③ (参考)Appiumのアーキテクチャ 45 Appium クライアントラ イブラリ スクリプト Appium サーバ テスト対象 アプリ HTTP (Mobile JSON Wire Protocol) EspressoやUI Automator を使って操作 クライアントPC サーバーPC スマートフォン USB

Slide 46

Slide 46 text

ⓒ 2020 DeNA Co., Ltd. 2. テストツール選択のポイント 46 1. EspressoとAppiumの概要 2. EspressoとAppiumの比較

Slide 47

Slide 47 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-2. EspressoとAppiumの比較① Appiumも内部でEspressoを使うようになった (Appium Espresso WebDriver)ので、 できることの違いはほとんど無くなった (違いの例) ● Espresso: RecyclerView専用API ● Appium: OpenCVによる画像検索API 47

Slide 48

Slide 48 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-2. EspressoとAppiumの比較② 48 Espresso Appium テスト実行速度 速い 遅い プログラミング言 語 Java・Kotlinのみ Ruby・JavaScript・Ja va・Kotlinなど テストランナーの 実行場所 Android端末内部(*) 通常のPC 環境構築 簡単 難しい 対応DeviceFarm 多い 少ない (*)Robolectricを使うことでlocal JVMでも実行可能

Slide 49

Slide 49 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-2. EspressoとAppiumの比較③ UIテストは実行速度が命! 以下の事情がなければEspressoを選ぶと良い ● 既にAppiumによる自動化ノウハウがある ● テスト自動化担当者がAndroidエンジニアではない ● Androidアプリ以外の操作を含むテストシナリオを自動 化したい 「PCブラウザで会員登録してから アプリでログインする」など 49

Slide 50

Slide 50 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 2-2. EspressoとAppiumの比較④ (参考) Appiumを選択する場合 パフォーマンス向上策の参考記事 ● Appium Pro #50 (Android向け) Special Capabilities for Speeding up Android Test Initialization https://appiumpro.com/editions/50 ● Appium Pro #77 (iOS向け) Optimizing WebDriverAgent Startup Performance https://appiumpro.com/editions/77 50

Slide 51

Slide 51 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 51 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. 検証結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 52

Slide 52 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 52 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. テスト結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 53

Slide 53 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-1. Page Objectデザインパターンを適用する ● 画面を1つのオブジェクトとして定義するデザインパ ターン ● テストコードを共通化する指針 ● 対象アプリのUI が変更されたときのテストコード修正 コストを小さくすることを目的としている DeNA Codelabs ( https://dena.github.io/codelabs/ ): 「Espressoの知識ゼロでも書ける!Android UIテストはじめの 一歩」 53

Slide 54

Slide 54 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. テストコードの共通化: テスト対象 54 ユーザーID パスワード ログイン invalid_user ********** ログイン ログインできません ログイン失敗 ようこそ! ログイン成功

Slide 55

Slide 55 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 55 @Test fun login_success() { //ユーザー名とパスワードを入力してログイン onView(withHint("ユーザーID")).perform(replaceText("valid_user")) onView(withHint("パスワード")).perform(replaceText("valid_password")) onView(withText("ログイン")).perform(click()) //ログインが成功して「ようこそ」と表示されている onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } @Test fun login_error() { // 不正なユーザー名とパスワードを入力してログインボタンをクリック onView(withHint("ユーザーID")).perform(replaceText("invalid_user")) onView(withHint("パスワード")).perform(replaceText("invalid_password")) onView(withText("ログイン")).perform(click()) // ログインエラーのメッセージが表示されている onView(withId(R.id.errorMessage)).check(matches(withText("ログインできません"))) } テストコードの共通化: 共通化前

Slide 56

Slide 56 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. テストコードの共通化: 共通化前 56 @Test fun login_success() { //ユーザー名とパスワードを入力してログイン onView(withHint("ユーザーID")).perform(replaceText("valid_user")) onView(withHint("パスワード")).perform(replaceText("valid_password")) onView(withText("ログイン")).perform(click()) //ログインが成功して「ようこそ」と表示されている onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } @Test fun login_error() { // 不正なユーザー名とパスワードを入力してログインボタンをクリック onView(withHint("ユーザーID")).perform(replaceText("invalid_user")) onView(withHint("パスワード")).perform(replaceText("invalid_password")) onView(withText("ログイン")).perform(click()) // ログインエラーのメッセージが表示されている onView(withId(R.id.errorMessage)).check(matches(withText("ログインできません"))) } 重複が多い

Slide 57

Slide 57 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. テストコードの共通化: 共通化前 57 @Test fun login_success() { //ユーザー名とパスワードを入力してログイン onView(withHint("ユーザーID")).perform(replaceText("valid_user")) onView(withHint("パスワード")).perform(replaceText("valid_password")) onView(withText("ログイン")).perform(click()) //ログインが成功して「ようこそ」と表示されている onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } @Test fun login_error() { // 不正なユーザー名とパスワードを入力してログインボタンをクリック onView(withHint("ユーザーID")).perform(replaceText("invalid_user")) onView(withHint("パスワード")).perform(replaceText("invalid_password")) onView(withText("ログイン")).perform(click()) // ログインエラーのメッセージが表示されている onView(withId(R.id.errorMessage)).check(matches(withText("ログインできません"))) } ボタン名が「ログインする」に 変更されたとき、2箇所修正が必要

Slide 58

Slide 58 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. テストコードの共通化: ログイン操作を共通化 58 @Test fun login_success() { onView(withHint("ユーザーID")).perform(replaceText("valid_user")) onView(withHint("パスワード")).perform(replaceText("valid_password")) onView(withText("ログイン")).perform(click()) onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } ログイン操作を 抽出

Slide 59

Slide 59 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 59 @Test fun login_success() { login("valid_user", "valid_password") onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } @Test fun login_error() { login("invalid_user", "invalid_password") onView(withId(R.id.errorMessage)).check(matches(withText("ログインできません"))) } private fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } テストコードの共通化: 共通化後

Slide 60

Slide 60 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 60 @Test fun login_success() { login("valid_user", "valid_password") onView(withId(R.id.welcomeMessage)).check(matches(withText("ようこそ! "))) } @Test fun login_error() { login("invalid_user", "invalid_password") onView(withId(R.id.errorMessage)).check(matches(withText("ログインできません"))) } private fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } テストコードの共通化: 共通化後 ボタン名が「ログインする」に 変更されたときの修正はここのみ

Slide 61

Slide 61 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Page Objectデザインパターンの考え方 1. テスト対象の画面ごとにクラス(Page クラス)を定義する 2. Page クラスにその画面が提供するサービスをメソッドとして定 義する a. アクションを実行するメソッド・ページ情報を取得するメソッドなど 3. アクションを実行するメソッドは戻り値として、 遷移先の画面に対応するPageオブジェクトを返す 4. テストコードではPageクラスのメソッドのみを使う 61

Slide 62

Slide 62 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Page Objectのサービス 62 ● 画面が提供するサービスとは何か?に着目し、メソッ ドとして定義する − 画面の詳細や構造はPage Objectの中に隠蔽 ● 例: ログイン画面 fun login(id, password) LoginPage fun inputID(id) fun inputPass(password) fun clickLogin() LoginPage

Slide 63

Slide 63 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログイン画面のテストにあてはめる 1. loginメソッドをLoginPageクラスに移動する 2. 画面に表示されるメッセージを検証するコードもそれぞれの Pageクラスに移動する a. ログイン成功時のメッセージ検証: MainPage b. ログイン失敗時のメッセージ検証: LoginPage 3. 各テストメソッドではPageクラスに定義されたメソッドのみ利用 する 63

Slide 64

Slide 64 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログイン画面のテストにあてはめる 64 test_login_success() test_login_failure() LoginTest login_success(id, password): MainPage login_failure(id, password): LoginPage assertErrorMessage(message): LoginPage LoginPage assertWelcomeMessage(message): MainPage MainPage 利用する

Slide 65

Slide 65 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログイン画面のテストにあてはめる 65 test_login_success() test_login_failure() LoginTest login_success(id, password): MainPage login_failure(id, password): LoginPage assertErrorMessage(message): LoginPage LoginPage assertWelcomeMessage(message): MainPage MainPage 利用する 画面ごとにPageクラスを 定義する

Slide 66

Slide 66 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. test_login_success() test_login_failure() LoginTest ログイン画面のテストにあてはめる 66 login_success(id, password): MainPage login_failure(id, password): LoginPage assertErrorMessage(message): LoginPage LoginPage assertWelcomeMessage(message): MainPage MainPage 利用する 戻り値は遷移先の画面の Pageクラスにする

Slide 67

Slide 67 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログイン画面のテストにあてはめる 67 test_login_success() test_login_failure() LoginTest login_success(id, password): MainPage login_failure(id, password): LoginPage assertErrorMessage(message): LoginPage LoginPage assertWelcomeMessage(message): MainPage MainPage 利用する テストコードはPageクラスの メソッドのみ用いて実装する

Slide 68

Slide 68 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 68 class LoginPage { fun loginSuccess(id: String, password: String): MainPage { login(id, password) return MainPage() } fun loginFailure(id: String, password: String): LoginPage { login(id, password) return this } private fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } .. ログインページクラスの実装: アクション

Slide 69

Slide 69 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログインページクラスの実装: アクション 69 class LoginPage { fun loginSuccess(id: String, password: String): MainPage{ login(id, password) return MainPage() } fun loginFailure(id: String, password: String): LoginPage { login(id, password) return this } fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } ..  画面のアクションをメソッドとして実装

Slide 70

Slide 70 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. class LoginPage { fun loginSuccess(id: String, password: String): MainPage { login(id, password) return MainPage() } fun loginFailure(id: String, password: String): LoginPage { login(id, password) return this } .. 遷移をせず画面にとどまる場合は thisを返す ログインページクラスの実装: アクション 70 戻り値はアクションをした後の 遷移先画面のPageクラス

Slide 71

Slide 71 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ログインページクラスの実装: アクション 71 class LoginPage { fun loginSuccess(id: String, password: String): MainPage{ login(id, password) return MainPage() } fun loginFailure(id: String, password: String): LoginPage { login(id, password) return this } private fun login(id: String, password: String) { onView(withHint("ユーザーID")).perform(replaceText(id)) onView(withHint("パスワード")).perform(replaceText(password)) onView(withText("ログイン")).perform(click()) } ..  各アクションで使われるログイン処理の 共通メソッド

Slide 72

Slide 72 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 72 class LoginPage { .. fun assertErrorMessage(message: String): LoginPage { onView(withId(R.id.errorMessage)) .check(matches(withText(message))) return this } .. } ログインページクラスの実装: アサーション ログイン失敗時の エラーメッセージ検証メソッド

Slide 73

Slide 73 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Pageクラスを用いたログインのテストコード 73 class LoginTest { @Test fun login_error() { LoginPage() .loginFailure("invalid_user", "invalid_password") .assertErrorMessage("ログインできません") } .. } テストコードはPageクラスの メソッドのみ用いて実装する

Slide 74

Slide 74 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Page Objectを実装するときのポイント 74 ● Pageクラスの外には画面UIの詳細を露出させない(レ イアウト構造など) ● 画面が提供するサービスをすべてPageクラスに実装 する必要はない ● 同じアクションでも遷移先が異なる場合は それぞれ別のメソッドにする

Slide 75

Slide 75 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Page Object参考リンク 75 ● SeleniumのPage Object解説 − https://github.com/SeleniumHQ/selenium/wiki/PageObjects − assertをテストケースで実装するなど、 Espressoを使っている場合は実現できない原則もある ● Martinfowler.com − https://martinfowler.com/bliki/PageObject.html

Slide 76

Slide 76 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. Page Objectデザインパターンのおさらい ● 画面を1つのオブジェクトとして定義するデザインパ ターン ● テストコードを共通化するときの指針であり、テスト コード修正コストを小さくすることが目的 ● Page Objectを適用させるときはこの目的を意識しな がら実装をする 76

Slide 77

Slide 77 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 77 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. 検証結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 78

Slide 78 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-2. CI環境でテストコードを動かし続ける ● CI 環境でUIテストを継続的に実行する − 自身以外の環境でもテストコードが動くことを確認する − 定期的な実行により、テストコードの安定性を確かめる − CI環境で実行することで運用に乗せやすくする ● UIテストはユニットテストと比較すると、実行環境や外 部要因の影響をうけやすく壊れやすい ● CI環境で継続して動かすことで安定性を確かめる 78

Slide 79

Slide 79 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 79 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. テスト結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 80

Slide 80 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-3. テスト結果をわかりやすく共有する 80 ● レポート形式でテスト結果を出力する ● Slackにテストの成功と失敗を通知する ● テスト失敗の原因がわかりやすいようにする − 失敗時のスクリーンショット・各種ログ・動画を保存する − 理由がわかりやすくなっていないと調査コストがかかる ● 直近の結果だけでなく今までの履歴も保存する − どのテストケースが不安定になっているかを確認できる

Slide 81

Slide 81 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-3. テスト結果をわかりやすく共有する 81 ● Allure: 多機能なテストレポート表示ツール − http://allure.qatools.ru/ − JUnit互換のテスト結果XMLがあれば表示できる − Android向けadapterもあり(発展途上) https://github.com/TinkoffCreditSystems/allure-android # インストール $ brew install allure # テスト実行 $ ./gradlew connectedAndroidTest # テスト結果レポートをAllureで表示 $ allure serve \ app/build/outputs/androidTest-results/connected/

Slide 82

Slide 82 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-3. テスト結果をわかりやすく共有する 82 ● Allure Adapter − テスト結果レポートの内容をカスタマイズできる テスト失敗時にスクリーンショットを自動で追加 − Android Instrumented Test向けは発展途上 https://github.com/TinkoffCreditSystems/allure-android

Slide 83

Slide 83 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 83 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. テスト結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 84

Slide 84 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-4. 不安定なテストの対策をする ● たまに失敗する不安定なテストを放置せずに 対処を決める ● 失敗が放置されている状況が続くと、テストの信頼性 もなくなってしまう ● 不安定なテストを捨てるという選択肢も検討する 84

Slide 85

Slide 85 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 85 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. テスト結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 86

Slide 86 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-5. 実行時間を短縮させる 86 ● UIテストは実行時間が課題 − 自動テストが落ちたときの対応が面倒になる − 自動テストの完了が待てない − 実行に1時間以上かかるケースもある − その結果失敗しても放置される、使われなくなる... ● 不必要なテストケースを作らない − テストピラミッドで推奨されるUIテストの割合は10% − UIテストとして追加が必要かを考える ● テストを並列実行する

Slide 87

Slide 87 text

ⓒ 2020 DeNA Co., Ltd. 3. 長くテストコードを利用 し続けるには 87 1. Page Objectデザインパターンを適用する 2. CI環境でテストコードを動かし続ける 3. テスト結果をわかりやすく共有する 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組み込む

Slide 88

Slide 88 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. 3-6. 開発やリリースフローに組み込む 88 ● 実装したUIテストは実際に運用され、開発フローで利 用されることで意味のあるものになる ● 開発・リリース時のフローに組み込むことで、 定期的にUIテストが実行される環境を作る − PR時に実行される − テストがパスしていないとPRのマージができない − 自動テストがすべてパスしていることがリリースの条件 etc...

Slide 89

Slide 89 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. ここまでのまとめ 1. Page Objectデザインパターンを適用する − テストコードを共通化して変更に強くしよう 2. CI環境でテストコードを動かし続ける 3. テスト結果もわかりやすく共有する − テスト失敗の原因がすぐわかるようにしよう 4. 不安定なテストを対策する 5. 実行時間を短縮させる 6. 開発・リリースフローに組込む 89

Slide 90

Slide 90 text

ⓒ 2020 DeNA Co., Ltd. 90 DeNA Codelabsで説明します! https://dena.github.io/codelabs/android-ui-tests-espresso 4. Espresso APIを使いこなして UIテストを書いてみよう

Slide 91

Slide 91 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. (付録) ショートカット一覧 Mac版 91 Action名 ショートカット 意味 Move Line Down Opt+Shift+↓ 選択範囲を下に移動する Change Signature Cmd+F6 メソッドシグネチャを変更する Move F6 (メソッドなどを) 別クラスや別ファイルに移動する Extract Function To Scope Opt+Shift+Cmd+M 選択範囲をメソッドとして抽出する Extract Parameter Opt+Cmd+P 選択箇所をメソッド引数にする Show Intention Actions Opt+Enter (空気を読んで) 必要なアクションを提案する Help>Find Action… で入力する名前 ショートカットを忘れたときに便利!

Slide 92

Slide 92 text

ⓒ 2019 DeNA Co., Ltd. ⓒ 2019 DeNA Co., Ltd. ⓒ 2020 DeNA Co., Ltd. (付録) ショートカット一覧 Windows版 92 Action名 ショートカット 意味 Move Line Down Alt+Shift+↓ 選択範囲を下に移動する Change Signature Ctrl+F6 メソッドシグネチャを変更する Move F6 (メソッドなどを) 別クラスや別ファイルに移動する Extract Function To Scope Ctrl+Alt+Shift+M 選択範囲をメソッドとして抽出する Extract Parameter Ctrl+Alt+P 選択箇所をメソッド引数にする Show Intention Actions Alt+Enter (空気を読んで) 必要なアクションを提案する Help>Find Action… で入力する名前 ショートカットを忘れたときに便利!