DroidKaigi 2016で発表した、AndroidのテストツールUI Automator 2についての資料です。
発表時のビデオはこちらをご参照ください。
⽣まれ変わったUI Automatorを使いこなす2016.2.19@sumio_tym (TOYAMA Sumio)1DroidKaigi 2016
View Slide
⾃⼰紹介• ⽒名: 外⼭ 純⽣ (TOYAMA Sumio)@sumio_tym (Twitter) / @sumio (GitHub)• 所属: NTTソフトウェア株式会社• 業務内容:社内Android関連プロジェクトの技術⽀援• プライベート:• STAR(テスト⾃動化研究会)• @IT連載「スマホ向け無料システムテスト⾃動化ツール」uiautomator/Appiumの回を書きましたhttp://www.atmarkit.co.jp/ait/kw/smapho_testtool.html2
お話しすること• 新しくなった⾃動テストツールUI Automator 2について説明します• 旧版(uiautomator)との違い• APIの基本的な使い⽅• Tips• UI Automater2の使いどころ3とにかく情報が少ない
話の流れ1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ4
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ5
UI Automator2の概要• Android SDK標準のテストツールhttp://goo.gl/E5DH9y (developer.android.com)• 特徴• ブラックボックステスト向け• 複数アプリにまたがったテスト(操作)ができる(ソースやapkが⼿元に無くてもテストできる)• ソースコードリポジトリhttps://goo.gl/ONClV1 (android.googlesource.com)※旧uiautomatorからリポジトリの場所が移動しているので注意• APIリファレンスhttp://goo.gl/alp382 (android.googlesource.com)6
旧uiautomatorとの違い旧uiautomator UI Automator2 UI Automator2対応APIレベル 16以上 18, 19 21以上IDE/ビルドツール Eclipse/ant Android Studio/Gradle実⾏⽅法uiautomatorコマンドInstrumentation Testテキスト⼊⼒ ASCIIのみ Unicodeパフォーマンス やや遅い 速い旧APIの利⽤ ○ △ ○新APIの利⽤ × △ ○7おすすめ!詳しくは https://goo.gl/mTP8ig 参照
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ8
準備: ファイル配置とbuild.gradle9EFQFOEFODJFT\BOESPJE5FTU$PNQJMFDPNBOESPJETVQQPSUUFTUSVOOFSBOESPJE5FTU$PNQJMFDPNBOESPJETVQQPSUUFTUSVMFTBOESPJE5FTU$PNQJMF=DPNBOESPJETVQQPSUUFTUVJBVUPNBUPSVJBVUPNBUPSW^for Instrumentation Testfor UI Automator2• テストコード格納先.0%6-&@%*3TSDBOESPJE5FTU• CVJMEHSBEMF
準備: 初期化10!3VO8JUI "OESPJE+6OJUDMBTTQVCMJDDMBTT.Z6JBVUPNBUPS5FTU\!3VMFQVCMJD"DUJWJUZ5FTU3VMFBDUJWJUZ5FTU3VMFQSJWBUF6J%FWJDFVJ%FWJDF!#FGPSFQVCMJDWPJETFU6Q UISPXT&YDFQUJPO\VJ%FWJDF6J%FWJDFHFU*OTUBODF *OTUSVNFOUBUJPO3FHJTUSZHFU*OTUSVNFOUBUJPO ^^6J%FWJDFを初期化しておく
準備: まとめ• 基本的な考え⽅はInstrumentation Test (Espressoなど)と同じ• TFU6Q で6J%FWJDFの初期化を忘れずに11
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ12
UI部品の検索と操作: 基本形13VJ%FWJDFGJOE0CKFDU ✝ᦴঽਃ• ✝ᦴঽに合致したUI部品をਃする• GJOE0CKFDU メソッドが2つ• 6J0CKFDUGJOE0CKFDU 6J4FMFDUPS• 6J0CKFDUGJOE0CKFDU #Z4FMFDUPS引数・戻り値の型に注⽬!
UI部品の検索と操作: 検索(1/2)14• GJOE0CKFDU メソッドが2つ• 6J0CKFDUGJOE0CKFDU 6J4FMFDUPS• 6J0CKFDUGJOE0CKFDU #Z4FMFDUPS• 6J4FMFDUPS検索条件の例(旧uiautomator互換)• #Z4FMFDUPS検索条件の例(UI Automator2 新API)OFX6J4FMFDUPS UFYU 0,DMBTT/BNF #VUUPODMBTT#ZUFYU 0,DMB[[ #VUUPODMBTT
UI部品の検索と操作: 検索(2/2)• 6J4FMFDUPS検索条件API• #Z4FMFDUPS検索条件API15メソッド 概要className(Class) Viewのクラス(EditTextやButtonなど)を条件に指定するtext(String) Viewの表⽰⽂字列を条件に指定するdescription(String) ViewのcontentDescription属性値を条件に指定するresourceId(String) ViewのリソースID(⽂字列表現)を条件に指定するメソッド 概要clazz(Class) Viewのクラス(EditTextやButtonなど)を条件に指定するtext(String) Viewの表⽰⽂字列を条件に指定するdesc(String) ViewのcontentDescription属性値を条件に指定するres(String) ViewのリソースID(⽂字列表現)を条件に指定する
UI部品の検索と操作: 操作(6J0CKFDU/6J0CKFDUともに同じメソッド名)16メソッド 概要click() クリックするsetText(String) 指定された⽂字列を⼊⼒するgetText() 設定されている⽂字列を取得するisFocused() フォーカスが当たっているかどうかを取得する
UI部品の検索と操作: 使⽤例「"OK"ボタン」をクリックする例176J4FMFDUPS6J0CKFDUӼਜҰ൶6J0CKFDUPL#VUUPOVJ%FWJDFGJOE0CKFDU OFX6J4FMFDUPS UFYU 0,DMBTT/BNF #VUUPODMBTTPL#VUUPODMJDL #Z4FMFDUPS6J0CKFDUӼਜҰ൶6J0CKFDUPL#VUUPOVJ%FWJDFGJOE0CKFDU #ZUFYU 0,DMB[[ #VUUPODMBTTPL#VUUPODMJDL
UI部品の検索と操作: 検索タイミング6J4FMFDUPS6J0CKFDUを使う場合• 6J0CKFDUの操作メソッドを呼び出したとき※GJOE0CKFDU 6J4FMFDUPS呼び出し時ではない• ⾒付からなかったら6J0CKFDU/PU'PVOE&YDFQUJPO• 画⾯レイアウトが変わっても同⼀6J0CKFDU使いまわせる#Z4FMFDUPS6J0CKFDUを使う場合• GJOE0CKFDU #Z4FMFDUPSを呼び出したとき• ⾒付からなかったらOVMMを返す• 画⾯レイアウトが変わると6J0CKFDUは無効になる→4UBMF0CKFDU&YDFQUJPO18
UI部品の検索と操作: 検索範囲指定あるUIサブツリーの下だけ検索する• UiSelector/UiObjectを使う場合:• BySelector/UiObject2を使う場合:196J4FMFDUPSDSJUFSJB✝ӘゼᾂDIJME4FMFDUPS ✝ᦴঽ6J0CKFDUUBSHFUVJ%FWJDFGJOE0CKFDU DSJUFSJB6J0CKFDUSPPUVJ%FWJDFGJOE0CKFDU ✝Әゼᾂ6J0CKFDUUBSHFUSPPUGJOE0CKFDU ✝ᦴঽ✝Әゼᾂ
UI部品の検索と操作: 検索範囲指定あるUIサブツリーの下だけ検索する• UiSelector/UiObjectを使う場合:• BySelector/UiObject2を使う場合:206J4FMFDUPSDSJUFSJBOFX6J4FMFDUPS SFTPVSDF*E.BUDIFT JEMBZPVUDIJME4FMFDUPS OFX6J4FMFDUPS UFYU 0,VJ%FWJDFGJOE0CKFDU DSJUFSJBDMJDL 6J0CKFDUSPPUVJ%FWJDFGJOE0CKFDU #ZSFT 1BUUFSODPNQJMF JEMBZPVUSPPUGJOE0CKFDU #ZUFYU 0,DMJDL 「layout2」の下にある「OK」ボタンを押す
UI部品の検索と操作: 検索範囲指定注意点: 「探索深さ」を指定したいとき216J0CKFDUSPPUVJ%FWJDFGJOE0CKFDU #ZSFT 1BUUFSODPNQJMF JEMBZPVUSPPUGJOE0CKFDU #ZUFYU 0,EFQUI DMJDL 「layout1」の直接の⼦供(探索深さ1限定)の「OK」ボタンを押したい• UiSelector/UiObjectを使う場合: 不可• BySelector/UiObject2を使う場合: EFQUI を使う
UI部品の検索と操作: スクロールスクロールすれば現れる画⾯外の部品操作22[Developer options]→[Show touches]をタップしたい6J4DSPMMBCMFMJTUOFX6J4DSPMMBCMF OFX6J4FMFDUPS DMBTT/BNF -JTU7JFXDMBTTEFW0QUJPOT-JTUTFU"T7FSUJDBM-JTU 6J0CKFDUTIPX5PVDIFTMJTUHFU$IJME#Z5FYU OFX6J4FMFDUPS DMBTT/BNF -JOFBS-BZPVUDMBTT 4IPXUPVDIFTTIPX5PVDIFTDMJDL GJOE0CKFDU 使わない「"Show touches"を⼦孫に持ったLinearLayout」を探す
UI部品の検索と操作: スクロールスクロールすれば現れる画⾯外の部品操作• 旧uiautomator時代のAPIしか無い• 6J4DSPMMBCMFは6J0CKFDUのサブクラス• いきなりOFXするスタイル• 気持ち悪いが割り切って使い続けるしかない23
UI部品の検索と操作: まとめ• ⽬的の似たAPIが2セット存在• UiSelector/UiObject (旧uiautomator互換)• BySelector/UiObject2 (新規追加)• 両者で検索タイミングが微妙に異なる• 操作時 vs findObject()時• 新しいBySelector/UiObject2は細かい部分で改善• 直接の⼦供の検索• スクロールサポートは旧APIのみ24
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ25
待ち合わせ: 概要• 原則: 操作による画⾯更新を待たずに次に進む• 独⽴した複数のボタン・テキストボックスを連続操作するときは速くて便利• 以下のようなケースでは同期(待ち合わせ)が必要• 直前の操作による画⾯の変化に依存した操作• ボタンを押すとTextViewの表⽰が変わることを確認したい• テキストボックスに⽂字を⼊⼒し、enabledになったボタンを押したい• etc.• ある操作で画⾯遷移・ダイアログ表⽰が発⽣するとき• 画⾯遷移・ダイアログ表⽰を完了してから次の操作をしたい26
待ち合わせ: UiSelector/UiObject6J0CKFDUの「操作+待ち合わせ」メソッドを呼ぶ27メソッド(引数はタイムアウト値) 概要clickAndWaitForNewWindow(long) クリックしてから、新しい窓(ダイアログなど)が表⽰されるまで待つwaitForExists(long) このViewが表⽰されるまで待つwaitUntilGone(long) このViewが消えるまで待つ※タイムアウトした場合は、falseが返されるѷ0,ѸՄԧ՛ӼᚭӁӐѬԨԌԊՕԘҶⷭ⒈ҿӶӵӨӑᑻӎ6J0CKFDUPL#VUUPOVJ%FWJDFGJOE0CKFDU OFX6J4FMFDUPS UFYU 0,DMBTT/BNF #VUUPODMBTTԨԌԊՕԘҶⷭ⒈ҿӶӵӨӑNTFDᑻӎѭԧԌՈԊԎᣪәԮԡႣᡇѭBTTFSU5IBU PL#VUUPODMJDL"OE8BJU'PS/FX8JOEPX - JT USVFҽҽҵӳⷭ⒈ҿӶӉԨԌԊՕԘӕሽӃӵਃӼҰ
待ち合わせ: BySelector/UiObject26J0CKFDUの汎⽤的なメソッドを呼ぶ28メソッド(引数は条件とタイムアウト値) 概要clickAndWait(EventCondition,long)クリックしてから、指定された条件が満たされるまで待つwait(SearchCondition, long) 指定された条件が満たされるまで待つwait(UiObject2Condition, long) 指定された条件が満たされるまで待つ※タイムアウトした場合は、null/0/falseが返される良く使う「条件」は6OUJMクラスに⽤意されているUntilクラスのstaticメソッド 概要newWindow() 新しい窓(ダイアログ)が表⽰されるまでgone(BySelector) 条件に合致するViewが⾒付からなくなるまでtextEquals(String) 表⽰⽂字列が引数で指定された通りになるまで
待ち合わせ: BySelector/UiObject229ѷ0,ѸՄԧ՛ӼᚭӁӐѬԨԌԊՕԘҶⷭ⒈ҿӶӵӨӑᑻӎ6J0CKFDUPL#VUUPOVJ%FWJDFGJOE0CKFDU #ZUFYU 0,DMB[[ #VUUPODMBTTԨԌԊՕԘҶⷭ⒈ҿӶӵӨӑNTFDᑻӎCPPMFBOSFTVMUPL#VUUPODMJDL"OE8BJU 6OUJMOFX8JOEPX -ԧԌՈԊԎӁӉӒҷәԮԡӼႣᡇҿӅӵBTTFSU5IBU SFTVMU JT USVFҽҽҵӳԨԌԊՕԘӘਃӔӓӼҰ
待ち合わせ: いつでも使えるものUiDeviceクラスのメソッドを呼ぶ30メソッド(引数はタイムアウト値) 概要wait(SearchCondition, long) 指定された条件が満たされるまで待つwaitForWindowUpdate(String,long)同⼀画⾯内のUIが更新されるまで待つ※第1引数はアプリのパッケージ名performActionAndWait(Runnable, EventCondition, long)指定されたアクション(Runnable)を実⾏し、条件が満たされるまで待つwaitForIdle(long) このアプリがアイドル状態になるまで待つ
待ち合わせ: 注意• OFX8JOEPX系とXJOEPX6QEBUF系の違い※間違うとタイムアウトするので注意• 新しい窓(ダイアログ含む)が表⽰されるとき: OFX8JOEPX系• 同じ窓の中が変化するとき: XJOEPX6QEBUF系• 待ち合わせメソッドの戻り値は必ずBTTFSUする• タイムアウトしても例外は発⽣しない• 「戻る」キー押下後の待ち合わせには6J%FWJDFXBJU 4FBSDI$POEJUJPO MPOHを使う(例)XBJU 6OUJMIBT0CKFDU #ZQLH UJNFPVU• 既存"DUJWJUZのSFTVNFは「新しい窓」ではない31
待ち合わせ: まとめ• 画⾯の変化を待ってから操作する場合は待ち合わせが必要• UiSelector/UiObject: 待ち合わせに使える条件が少ない• ある程度UiDeviceのメソッドでカバー可能• BySelector/UiObject2: 待ち合わせ条件を柔軟に指定可能• Untilクラスに良く使う待ち合わせ条件がまとまっている• こまかい注意事項あり• OFX8JOEPX vs XJOEPX6QEBUF• 待ち合わせの成功確認は⼤事!• 戻るボタン後の画⾯遷移32
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ33
UIの監視: UiWatcher• 6J8BUDIFS:⽬的のUI部品が⾒つからなかったときに発動するリスナ• リスナ発動後にUI部品の検索・操作をリトライする。• ユースケース: テストを失敗しにくくするのに有効!• ⾊々な画⾯で表⽰されるダイアログを操作する(セッション切れ時のログイン画⾯、レビューお願い画⾯、etc)• ANR/強制終了ダイアログを閉じてテストを続⾏する• etc.• 詳細は以下のURLで!※古い記事ですが考え⽅は同じです• http://sumio.hatenablog.com/entry/2014/04/06/01494134
UIの監視: 注意点• リスナ発動タイミング• 6J0CKFDUの操作メソッド呼び出し時UI部品が⾒つかるか、タイムアウトするまで、1秒おきに何回も呼び出される• GJOE0CKFDU #Z4FMFDUPS呼び出し時UI部品が⾒つからなかったらWindow1つにつき1回だけ呼び出される• Espressoとは連携しない• EspressoのAPI(PO7JFX で⾒付からなかったとき)では発動しない※混ぜて使うときは注意!35
タイムアウト値: 定義• $POGJHVSBUPSクラスに4種類存在Idle Timeout:アクセシビリティイベントキューのアイドル待ち時間Selector Timeout:UI部品が⾒えるまでの待ち時間Action Acknowledgment Timeout:UI部品操作が完了するまでの待ち時間Scroll Acknowledgment Timeout:スクロール操作が完了するまでの待ち時間36
タイムアウト値: 待つタイミング• Idle Timeout• Home/Backキーなど押下直前(この時間内にアイドル状態にならなければ諦めてキーを押す)• 6J0CKFDUを検索・操作する直前(この時間内にアイドル状態にならなければ諦めて検索・操作する)• Selector Timeout• 6J0CKFDUを検索するとき(この時間内に⾒付からなければ諦める)• Action Acknowledgment Timeout• 6J0CKFDUを操作するとき(この時間内に操作が完了しなければ諦める)37
タイムアウト値: 待つタイミング利⽤するAPI(クラス)によって、使われるタイムアウト値が異なる点に注意!38UiDevice UiObject UiObject2Idle Timeout ○ × ○Selector Timeout × ○ ×Action Acknowledgment Timeout × ○ ×
WebViewの操作• 検索・操作できるような"1*は無い• 6J%FWJDFHFU-BTU5SBWFSTFE5FYU • 「最後に選択されたテキストを返す」• %1BEでフォーカス移動Ȕ移動する度にこのメソッドを呼ぶと現在位置がわかる Ȕ⽬的のテキストに辿りついたら%1BEで操作する• ⾊々やってみてもOVMMしか返してくれない• 8FC7JFXも操作したい場合はAppiumがおすすめ詳しくは@ITの記事を参照• http://goo.gl/lsw8xf• http://goo.gl/rUHIb839
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ40
使いどころ: Espressoとの併⽤• 1つのテストメソッド内でEspresso・UI Automator両⽅のAPIを併⽤可能• 基本Espressoでテストを書く• Espressoでテストできない箇所だけUI Automatorを使う• 併⽤は簡単• UiDeviceをsetUp()時に初期化しておけばOK• ⾃由に混ぜて利⽤可41
使いどころ: ユースケース• 事前条件のセットアップ• ロケールを切り替えてからテストを開始する• WiFiをOFFにしてからテストを開始する• etc.• システムダイアログの操作• MarshmallowのRuntime Permissionダイアログ操作• ANR/強制終了ダイアログの操作• 連携先アプリの操作42
使いどころ: Espresso併⽤時の注意点世界を切り替えるときには待ち合わせを忘れずに&TQSFTTPȒȔ6*"VUPNBUPS43㘘⼱ᎅӕԊԗԣԡӃӵӉӫӘՄԧ՛ӼᚭӃPO7JFX XJUI*E [email protected]QFSGPSN DMJDL ԹդՇԫԟՏ՛⽇ԨԌԊՕԘӼਃVJ%FWJDFXBJU 6OUJMGJOE0CKFDU #ZSFT DPNBOESPJEQBDLBHFJOTUBMMFS [email protected]@CVUUPO 5*.&[email protected]"-6&DMJDL Ꮜ㘘⼱ᎅԊԗԣԡՄԧ՛ӼᚭӃVJ%FWJDFXBJU 6OUJMIBT0CKFDU #ZSFT 1BUUFSODPNQJMF [email protected] 5*.&[email protected]"-6&PO7JFX XJUI*E [email protected]QFSGPSN DMJDL UI Automatorで操作したいボタンが表⽰されるまで待つEspressoで操作したいボタンが表⽰されるまで待つ
1. 概要2. 基本的な使い⽅• 準備• UI部品の検索と操作• 待ち合わせ3. Tips4. UI Automator2の使いどころ5. まとめ44
まとめ• UI Automator2について解説しました• Espressoでテストできない箇所だけUI Automator2の助けを借りると、スモールスタートできます• 6J0CKFDU vs 6J0CKFDUの微妙な違いに注意!• スクロールが必要なところ以外は6J0CKFDUを使っておけば安⼼• 細かい点で困ったらこの資料を思い出してみてください45ご清聴ありがとうごうございました