Slide 1

Slide 1 text

  ΋͠΋ͷ࣌ʹ΋҆৺ͳ   uiautomatorͷwatcherػೳ 2014.04.03   @sumio_tym  (TOYAMA  Sumio) android.casual.test  #02

Slide 2

Slide 2 text

ࣗݾ঺հ •  ࢯ໊:  ֎ࢁ७ੜ(TOYAMA  Sumio)   @sumio_tym  (twitter),  @sumio  (github)   http://sumio.hatenablog.com/  (blog)   •  ॴଐ:  NTTιϑτ΢ΣΞגࣜձࣾ   •  ۀ຿಺༰:   – ࣾ಺Android™ؔ࿈ϓϩδΣΫτٕज़ࢧԉ   – Androidؔ࿈ࣾ಺ݚमߨࢣ   •  ϓϥΠϕʔτ:   – Androidͷࣗಈςετ༻ͷIMEΛެ։ͯ͠·͢   https://github.com/sumio/uiautomator-­‐unicode-­‐input-­‐helper   ()  Android  is  a  trademark  of  Google  Inc. 2  

Slide 3

Slide 3 text

•  uiautomator:  AndroidͷUIςετπʔϧ   •  UiWatcher:    uiautomatorͷAPI   3   ͓࿩͢͠Δ͜ͱ uiautomatorΛ࢖ͬͨࣗಈςετΛ   ΑΓrobustʹ͢ΔAPI   ʮUiWatcherʯػೳʹ͍ͭͯઆ໌͠·͢

Slide 4

Slide 4 text

ΞδΣϯμ •  uiautomator͓͞Β͍   •  UiWatcherΛ࢖Θͳ͍ͱى͖Δ͜ͱ   •  UiWatcherͱ͸   – ֓ཁ   – ࢖͍ํ   – Tips  1:  UiWatcherൃಈλΠϛϯά   – Tips  2:  checkCondition()ͷ໭Γ஋   •  ·ͱΊ   4  

Slide 5

Slide 5 text

uiautomator͓͞Β͍ 5  

Slide 6

Slide 6 text

uiautomator͓͞Β͍   ֓ཁ •  ػೳɾUIςετࣗಈԽπʔϧ(Googleۘ੡)   –  http://developer.android.com/tools/testing/ testing_ui.html   •  ಛ௃   –  ΞϓϦʹ·͕ͨͬͨૢ࡞γφϦΦ͕ॻ͚Δ   –  ୈࡾऀ͕࡞ͬͨΞϓϦ΋ૢ࡞Մೳ   –  ઈର࠲ඪࢦఆ͕ෆཁ   •  ཹҙ఺   –  JellyBean  (API  Level  16)Ҏ্ͷΈରԠ   –  ൺֱతγφϦΦ͕ෳࡶʹͳΓ͕ͪ   cf.  Robotium,  Espresso   6  

Slide 7

Slide 7 text

uiautomator͓͞Β͍   ςετίʔυྫ(1/2) •  ςετର৅ΞϓϦ   –  ϘλϯΛԡ͢ͱμΠΞϩάΛදࣔ͢Δ͚ͩ   7  

Slide 8

Slide 8 text

uiautomator͓͞Β͍   ςετίʔυྫ(2/2) 8   public void test_dialogA() throws Exception { // ʮμΠΞϩάදࣔAʯϘλϯΛԡ͠ɺμΠΞϩά͕දࣔ͞ΕΔ·Ͱ଴ͭɻ UiObject button = new UiObject(new UiSelector().text("μΠΞϩάදࣔA")); button.clickAndWaitForNewWindow(); // ʮμΠΞϩάදࣔAʯͱදࣔ͞Ε͍ͯΔTextViewͷଘࡏΛ֬ೝ͢Δɻ UiObject dialogMessage = new UiObject(new UiSelector() .className(TextView.class).text("μΠΞϩάදࣔA")); assertTrue("Dialog not found", dialogMessage.exists()); // ʮCloseʯϘλϯΛԡͯ͠μΠΞϩά͕ফ͑Δ·Ͱ଴ͭɻ UiObject dialogOk = new UiObject(new UiSelector() .className(Button.class).text("Close")); dialogOk.click(); assertTrue("μΠΞϩά͕ফ͑·ͤΜͰͨ͠", dialogMessage.waitUntilGone(10000L)); } UI෦඼ͷݕࡧ৚݅

Slide 9

Slide 9 text

UiWatcherΛ࢖Θͳ͍ͱى͖Δ͜ͱ 9  

Slide 10

Slide 10 text

UiWatcherΛ࢖Θͳ͍ͱى͖Δ͜ͱ   ΞϓϦ͕Ϋϥογϡ͢Δ৔߹(1/2) •  ΋͠΋ɺςετର৅ΞϓϦ͕   [μΠΞϩάB]ϘλϯΛԡ͢ͱΫϥογϡͨ͠Β?   10  

Slide 11

Slide 11 text

UiWatcherΛ࢖Θͳ͍ͱى͖Δ͜ͱ   ΞϓϦ͕Ϋϥογϡ͢Δ৔߹(2/2) 11   ςετγφϦΦʹ   ͱͬͯ͸૝ఆ֎! ޙଓͷςετ͸શࣦͯഊ! 100݅த1݅໨ͷςετͰΫϥογϡͨ͠Βɺ   ൵͍͠

Slide 12

Slide 12 text

UiWatcherͱ͸ 12  

Slide 13

Slide 13 text

UiWatcherͱ͸   ֓ཁ(1/2) •  ૢ࡞ର৅͕ݟ෇͔Βͳ͔ͬͨΒൃಈ͢ΔϦεφ   •  Ϧεφͷ۩ମྫ   –  ʮڧ੍ऴྃμΠΞϩάͷ[OK]Λԡ͢ʯ   –  ʮANRμΠΞϩάͷ[OK]Λԡ͢ʯ   –  etc.   13   ςετγφϦΦʹͱͬͯ૝ఆ֎ͷ͜ͱ͕ى͖͍ͯΔ

Slide 14

Slide 14 text

UiWatcherͱ͸   ֓ཁ(2/2) 14   ڧ੍ऴྃ UiWatcher͕ൃಈͯࣗ͠ಈతʹ[OK]Λԡ͢ ʮڧ੍ऴྃμΠΞϩάͷ[OK]Λԡ͢ʯUiWatcherΛ༧Ίొ࿥ ࠷ޙ·Ͱςετ͕ਐΉ!   خ͍͠

Slide 15

Slide 15 text

UiWatcherͱ͸   ࢖͍ํ 1.  UiWatcherͷ࣮૷ΫϥεΛ࡞Δ   –  public  boolean  checkCondition();   2.  ্هΛΠϯελϯεԽͯ͠ొ࿥͢Δ   –  setUp()ʹॻ͍͓ͯ͘ͷ͕Φεεϝ   3.  tearDown()࣌ʹొ࿥Λղআ͢Δ   15  

Slide 16

Slide 16 text

•  UiWatcherͷ࣮૷Ϋϥεྫ   16   private final UiWatcher crashWatcher = new UiWatcher() { @Override public boolean checkForCondition() { UiObject dialogContent = new UiObject(new UiSelector() .text("໰୊͕ൃੜͨͨ͠ΊɺDialogSampleΛऴྃ͠·͢ɻ")); if (!dialogContent.exists()) { return false; } UiObject okButton = new UiObject(new UiSelector() .className(Button.class).text("OK")); try { okButton.click(); } catch (UiObjectNotFoundException e) { return false; } dialogContent.waitUntilGone(10000L); return true; } }; ڧ੍ऴྃμΠΞϩά൑ఆ [OK]ϘλϯΛԡͯ͠μΠΞϩάΛফ͢ ࣗ෼ͷग़൪͡Όͳ͔ͬͨ࣌͸falseΛฦ͢ɻ

Slide 17

Slide 17 text

•  setUp()ͱtearDown()ͷྫ   17   private final UiWatcher crashWatcher = ...; // લεϥΠυࢀর private static final String CRASH_WATCHER_STRING = "Crash"; protected void setUp() throws Exception { super.setUp(); getUiDevice() .registerWatcher(CRASH_WATCHER_STRING, crashWatcher); // (ޙུ) } protected void tearDown() throws Exception { getUiDevice().resetWatcherTriggers(); getUiDevice().removeWatcher(CRASH_WATCHER_STRING); // (தུ) super.tearDown(); } UiWatcherʹϢχʔΫͳ໊લΛ෇͚ͯొ࿥ ొ࿥࣌ʹ෇໊͚ͨલΛࢦఆͯ͠ొ࿥ղআ

Slide 18

Slide 18 text

UiWatcherͱ͸   Tips  1:  UiWatcherൃಈλΠϛϯά(1/2) •  UI෦඼ʹର͢Δૢ࡞໋ྩΛड͚ͨͱ͖ͷಈ࡞   1.  ૢ࡞ର৅෦඼Λ୳͢   2.  ݟ෇͔ͬͨ৔߹:  ෦඼Λૢ࡞ͯ͠ൈ͚Δ   3.  ݟ෇͔Βͳ͔ͬͨ৔߹:   •  UiWatcherΛൃಈ͢Δ   •  1ඵεϦʔϓ͔ͯ͠Βretry͢Δ   •  λΠϜΞ΢τ͢ΔͱUiObjectNotFoundException   18   ૢ࡞ର৅͕ݟ෇͔Βͳ͔ͬͨͱ͖   ૢ࡞ର৅͕ݟ෇͔Βͳ͍͔΋஌Εͳ͍ͱ͖ retryͷ౓ʹൃಈ͢Δ   •  ಉҰUI෦඼ʹରͯ͠ෳ਺ճൃಈ͢Δ͜ͱ͕͋Δ   •  UI෦඼͕༗Δ(retryޙʹݟ෇͔ͬͨ)ͷʹൃಈ͢Δ͜ͱ͕͋Δ  

Slide 19

Slide 19 text

UiWatcherͱ͸   Tips  1:  UiWatcherൃಈλΠϛϯά(2/2) •  ޡര͠ͳ͍Α͏ʹ஫ҙͯ͠checkCondition()Λ࣮ ૷͢Δ͜ͱ͕େࣄ   –  ࠓճͷྫͰ͸ʮڧ੍ऴྃμΠΞϩάʯ͕දࣔ͞Εͯ ͍ͳ͍ͱ͖ʹؒҧͬͯOKΛԡ͞ͳ͍Α͏ʹ͢Δ   19   @Override public boolean checkForCondition() { UiObject dialogContent = new UiObject(new UiSelector() .text("໰୊͕ൃੜͨͨ͠ΊɺDialogSampleΛऴྃ͠·͢ɻ")); if (!dialogContent.exists()) { return false; } // (ޙུ) } }; ಉҰͷςΩετ͕ɺ   ΞϓϦ಺ʹग़ݱ͢Δͱޡര͢ΔͷͰ஫ҙ  

Slide 20

Slide 20 text

UiWatcherͱ͸   Tips  2:  checkCondition()ͷ໭Γ஋(1/2) •  UiWatcher͝ͱʹʮτϦΨʔঢ়ଶʯ͕͋Δ   •  checkCondition()͕trueΛฦ͢ͱτϦΨʔঢ়ଶ΋trueʹ   •  Ұ౓trueʹͳͬͨτϦΨʔঢ়ଶ͸໌ࣔతʹreset͢Δ· Ͱtrueͷ··   •  ૝ఆ͞ΕΔϢʔεέʔε   –  ڧ੍ऴྃ͞Εͨճ਺Λ਺͍͑ͨ   –  ڧ੍ऴྃ͞Ε͔ͨͲ͏͔ͰγφϦΦΛ෼ذ͍ͤͨ͞   –  etc.   20   ʮτϦΨʔঢ়ଶΛtrueʹ͢Δ͔Ͳ͏͔ʯΛද͢

Slide 21

Slide 21 text

UiWatcherͱ͸   Tips  2:  checkCondition()ͷ໭Γ஋(2/2) •  τϦΨʔঢ়ଶؔ࿈ͷAPI  (UiDeviceΫϥε)   –  setWatcherTriggered(String  watcherName)   –  hasWatcherTriggered(String  watcherName)   –  resetWatcherTriggers()   –  hasAnyWatcherTriggered()   •  UiWatcherొ࿥ղআͱͷؔ܎   –  ొ࿥ղআͯ͠΋τϦΨʔঢ়ଶ͸ΫϦΞ͞Εͳ͍   –  ొ࿥ղআ࣌͸resetWatcherTriggers()΋ݺΜͰ͓͘ͱ٢   21  

Slide 22

Slide 22 text

·ͱΊ •  uiautomatorͷUiWatcherʹ͍ͭͯઆ໌͠·ͨ͠   –  UI෦඼͕ݟ෇͔Βͳ͔ͬͨ࣌ʹݺͼग़͞ΕΔϦεφ   –  ςετର৅ΞϓϦʹࢥΘ͵ࣄଶ͕ൃੜͯ͠΋ςετ Λଓ͚ΒΕΔΑ͏ʹͳΓ·͢   •  UiWatcherͷࡉ͔͍ৼΔ෣͍Λઆ໌͠·ͨ͠   –  ൃಈλΠϛϯά   –  τϦΨʔঢ়ଶ   22   ׆༻ͯ͠ɺΑΓrobustͳςετΛ໨ࢦ͠·͠ΐ͏!