次ã«ã AppsConf 2017ã§ã®Mikhail Domrachevã®ã¹ããŒãã®ãã³ãŒãã§ãå®éã«iOSãããžã§ã¯ãã«UIãã¹ããçµã¿èŸŒãæ¹æ³ã«ã€ããŠè©±ããæ¬åœã«å¿ èŠãªãšããšäžèŠãªãšãã®èããå ±æããŸããã
å°æ¥ãèŠæ®ããŠãé·æãšçæãããããšã«æ³šæããŠãã ããã ããããç§ãã¡ã®æèŠã§ã¯ãæåãã¹ãã®è«å€§ãªäººä»¶è²»ãªãã§èšèšãã°ã®æ°ãå€§å¹ ã«åæžããããšã¯ã誰ããããããªå°é£ã䌎ãããšã§è©ŠããŠã¿ãã¹ãåŠå®ã§ããªãå©ç¹ã§ãã
èæ¯
èšèšã®åé¡ã«çŽé¢ããåã«ããããžã§ã¯ãã®èª¬æããé ãããå§ããŸãããã
- ãã®ãããžã§ã¯ãã¯2幎é掻çºã«çºå±ãç¶ããŠãããé·æçãšèšããŸãã
- éçºããŒã ã¯æé·ããŠããŸãã
- ãã®ãããžã§ã¯ãã¯ãå ±éã®æ©èœãåããå€ãã®ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã§æ§æãããŠããŸãã
- ã³ã¢ãã¬ãŒã ã¯ãŒã¯ãéçºãããŸããããã®ãã¬ãŒã ã¯ãŒã¯ã§ã¯ãäžè¬çãªæ©èœã匷調衚瀺ããããããªãµãã¢ãžã¥ãŒã«ã®åãããžã§ã¯ãã«æ¥ç¶ãããŠããŸãã
ç§ãã¡ã¯ãããŸããŸãªåœã«æ¯åºãæã€ããªã倧ããªå€è³ç³»éèäŒç€ŸãšååããŠããŸãã ååœã«ã¯ç¬èªã®ã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ããããå ±éã®æ©èœãåããŠããŸãããåœã®ãã¶ã€ã³ãç¹å®ã®ç¹ã§ç°ãªããããšãã°æ³åŸã«é¢é£ä»ããããŠããŸãã
æè¡é¢
ãã¹ãŠã®ç»é¢ã¯è¡šåœ¢åŒã§å®è£ ãããŠããŸãã ããŒãã«ã¯ãã»ã«ããã®ãã¥ãŒã¢ãã«ãªã©ã®ãã³ãã«ã®ã»ããã§æ§æãããŸãã ã€ãŸããView-Modelã䜿çšããŠã»ã«ã®ã³ã³ãã³ããã«ã¹ã¿ãã€ãºããç¹å®ã®ãã¶ã€ã³ãèšå®ããããšãã§ããŸããåœã«ãã£ãŠå€èŠ³ã¯ç°ãªããŸãããå®éã«ã¯Coreãã¬ãŒã ã¯ãŒã¯ã«ããã®ã¯åããªãœãŒã¹ã§ãã
å³ã¯ç»é¢ã瀺ããŠããŸãã äžéšã®ã»ã«ã«ã¯ç¬èªã®ãã¥ãŒã¢ãã«ãããããããä»ããŠæ¬¡ã®ããšãã§ããŸãã
- èæ¯è²ãã«ã¹ã¿ãã€ãºãã
- ãªãœãŒã¹ããååŸããç»åã®ååïŒimageNameïŒãèšå®ããŸãã
ãã¿ã³ã®è¡šç€ºã¢ãã«ã§ã¯ã次ãèšå®ã§ããŸãã
- ã³ã³ãã³ãïŒã¿ã€ãã«ïŒã
- ãã¶ã€ã³ïŒã¿ã€ãã«ã®è²ïŒã
- ãã®ãã¿ã³ã®èæ¯è²ã
ã³ã¢ãã¬ãŒã ã¯ãŒã¯
å¹³åããŠãæ°ããã¢ããªã±ãŒã·ã§ã³ããšã«ãCoreãã¬ãŒã ã¯ãŒã¯ã®æ©èœã®çŽ70ïŒ ãåå©çšãã30ïŒ ã ããæ°ãããã®ãååŸããŸãã
ã³ã¢ãã¬ãŒã ã¯ãŒã¯ã«ã¯æ¬¡ã®å ŽæããããŸãã
- ç»é¢ã¢ãžã¥ãŒã« -ã¢ãžã¥ãŒã«åœ¢åŒã®æ¢è£œç»é¢ã ç§ã¯ããããã¢ãžã¥ãŒã«ãšåŒãã§ããŸãããªããªãã圌ãã¯ãã§ã«ããã€ãã®æšæºçãªããžãã¹ããžãã¯ãå®è£
ããä»ã®ç»é¢ãžã®ç§»è¡ãã«ãŒãã£ã³ã°ããããã©ã«ãã®ãã¶ã€ã³ãããããã§ãã
- ä»»æã®ãµãŒãã¹ -ããšãã°ããããã¯ãŒã¯ãããŒã¿ãã£ãã·ã¥ãªã©ã®æäœã®ããã®ããŸããŸãªåºæ¬ãµãŒãã¹
- Utilsã¯ãã³ãŒãã®èšè¿°ãé«éåããã®ã«åœ¹ç«ã€ã«ããŽãªïŒãã«ããŒïŒã§ãã
- èšèšèŠçŽ -以äžã§æ§æããããã¹ãŠã®èšèšèŠçŽ ïŒ
- ãã¹ãŠã®ã»ã«ã®xib ïŒ
- cell-ãããã®ã»ã«ã®ã¯ã©ã¹
- ãã¥ãŒã¢ãã« ã
æ°ããã¢ããªã±ãŒã·ã§ã³ããšã«ã次ãè¿œå ããå¿ èŠããããŸãã
- ç»é¢ã¢ãžã¥ãŒã«ã®ãªãŒããŒã©ã€ã-Coreãã¬ãŒã ã¯ãŒã¯ã®ç»é¢ããªãŒããŒã©ã€ãããŸãã
- æ°ããç»é¢ã¢ãžã¥ãŒã« âãããã®æ©èœãã©ãã§ãåå©çšãããªãå Žåã®æ°ããç»é¢ ã
- ãµãŒãã¹ã®ãªãŒããŒã©ã€ã -éåžžããã¹ãŠã®åœã®APIãå®å
šã«åäžã«æ©èœããããã§ã¯ãªãããããããã¯ãŒã¯ãµãŒãã¹ãåå®çŸ©ããå¿
èŠããããŸãã
- xib-ã»ã«ã®æ°ãããã¶ã€ã³ãéçºããå¿
èŠãããå ŽåããããŸãã
éåžžããã¹ãŠã®ã»ã«ã¯ã³ã¢ããååŸãããŸãã View-Modelã䜿çšããŠãã¶ã€ã³ãã«ã¹ã¿ãã€ãºã§ããŸãããããã¯éåžžã«æ®éçã§ãããæçµçã«ãã¶ã€ã³ã¯Legoã®åœ¢åŒã«ãªããŸãã
ãã®çµæããã®ãããªããã©ã³ã±ã³ã·ã¥ã¿ã€ã³ããåŸãããŸãã
äŸ
ããã¯åãç»é¢ã§ãããåœãç°ãªããŸãã å ±éã®åºæ¬å®è£ ãã€ãŸãCoreã§ããã°ã©ãã³ã°ãããŠããŸãã è±ãåçã®ããŸããŸãªã«ããŽãªãéããŠãã¶ã€ã³ã®éããå®çŸããŠããŸãã ããèŠããšã次ã®ãããª10ã®éããèŠã€ããããšã¯ã»ãšãã©ã§ããŸããã
- ç°ãªãåçããªãœãŒã¹ã®ç°ãªãåœã§ã¯ãåãååã®ç°ãªãåçããããŸãã
- é»åã®ç°ãªãèæ¯ã
- æ
å ±ã®ç°ãªãé
眮ãšãããã«ç°ãªããã©ã³ãã
- ãã¿ã³ã®ç°ãªãè²
2çªç®ã®ã¿ã€ãã®ç»é¢ã¯ããã§ã«ããè€éã§ãã å·ŠåŽã¯ã³ã¢ãã¬ãŒã ã¯ãŒã¯ã®åºæ¬çãªå®è£ ã§ãããå³åŽã¯æ°ããåœã®é¡§å®¢ãåãæ å ±ããããã«ç°ãªãæ¹æ³ã§è¡šç€ºããããšã«ãããã®ã§ãã ããžãã¹ããžãã¯ã¯ä¿æãããŠããŸãããæ°ããèšèšãè¡ãå¿ èŠããããŸããã ä»ã®ã»ã«ïŒCoreãã¬ãŒã ã¯ãŒã¯ãããïŒã䜿çšããã¯ã¬ãžããã«ãŒãã«ããæ¯æããšããæ°ããæ©èœãå®è£ ããŸããã
ãã¹ãŠãé 調ã§ããããã«èŠãã顧客ã¯éåžžã«åãã§ãããé床ãäžããŠæ°ããåœãããéãããããšãææ¡ããŸããã ãããããã¡ããããã¹ãŠãèæ ®ããŠããŸããã§ããã
åé¡ã®åå
- æ°ããéçºè
ãããžã§ã¯ãã®å¢ããå¢ãããã«ãæ°ããéçºè ãæ¡çšãããŸããã
- å
±æãªãœãŒã¹
ãã§ã«è¿°ã¹ãããã«ããã¹ãŠã®åœã«å ±éã®ãªãœãŒã¹ãããããããã¯ãããªãã¯ãã¡ã€ã³ã§ãã æ°ããéçºè ïŒãŸãã¯å€ãéçºè ã§ãïŒã¯ããã©ã¡ãŒã¿ãå€æŽããããå ±æãªãœãŒã¹ã®èŠçŽ ã移å/å€æŽãããã§ããŸãã ãã¡ããã誰ãããããè¡ãã¹ãã§ã¯ãªãããšãç解ããŠããŸãããããã§ãäºäŸã¯ãããŸããã
- ãã¶ã€ããŒã¯ãã¢ããªã±ãŒã·ã§ã³ã®çµ±äžã¹ã¿ã€ã«ãå¿ããŠããŸãã
ãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã®ã¹ã¿ã€ã«ã¯åãã§ããããšãã°ãåãããã¹ãé 眮ãç¹å®ã®ã»ã«ã®è²ãåãèæ¯ãªã©ã§ãã æéãçµã€ã«ã€ããŠããã¶ã€ããŒã¯ãã®åäžã®ã¹ã¿ã€ã«ãå¿ãå§ããããŒã¹ã»ã«ã®ã¹ã¿ã€ã«ãå€æŽã§ããããã«ãªããŸããã ããã圌ã¯ãããããããšã§ããŸã£ããå¥ã®ã¢ããªã±ãŒã·ã§ã³ã«å®³ãåãŒãå¯èœæ§ããããšã¯èããŠããŸããã§ããã ãããŠãããã«é¢äžããŠããéçºè ãã圌ã被害ãåããããšãç¥ããŸããã§ããã ãã®çµæãæåãã¹ãäžã«ããå·Šãèšèšã«åžžã«ããã€ãã®åé¡ããããŸããã
ãããã®åé¡ã®è§£æ±ºçã¯ãUlãã¹ãã®å°å ¥ã§ããããšãããã«ããããŸããã Ulãã¹ããå°å ¥ããåã«ãiOSãããžã§ã¯ãã§ãããè¡ãããšãã§ããããŒã«ã®åžå Žã«ã€ããŠå°ãåæããŸããããä»ã®ãã©ãããã©ãŒã ã«ã€ããŠã¯èæ ®ããŸããã§ããã
Ulãã¹ãããŒã«ïŒ
- Appleã®iOS Ulãã¹ã
- appiumã¯çŸåšãããŸããŸãªãªãã¬ãŒãã£ã³ã°ã·ã¹ãã çšã®çµ±äžããããã¹ããèšè¿°ããããã®æã人æ°ã®ãããã¬ãŒã ã¯ãŒã¯ã§ãã äžè¬çãªãã¹ããäœæããŠãããŸããŸãªãã©ãããã©ãŒã ã«ãšã¯ã¹ããŒãã§ããŸãã
- Calaba.sh -XamarinãéçºãããªãŒãã³ãã¬ãŒã ã¯ãŒã¯ã«ã¯ãããŸããŸãªãã©ãããã©ãŒã çšã®äžè¬çãªãã¹ãã®äœæãå«ãŸããŸãã
æ確ãªåºæºã«åŸã£ãŠåæãè¡ããŸããã
- ã³ã¹ãã æ©èœãªãã®åºæ¬æ§æã®ãã¹ãŠã®è£œåã¯ç¡æã§ãéçºè
ã¯ãããžã§ã¯ãã«åºå®ããŠäœ¿çšã§ããŸãã
- ã¯ãã¹ãã©ãããã©ãŒã ã ããã¯ç§ãã¡ã«ãšã£ãŠããã»ã©éèŠã§ã¯ãããŸããã§ããããåæã§ã¯ãã®åºæºãèæ
®ããŸããã
- ã³ãŒãçæãã€ãŸããã¹ãèšé²ã®å¯èœæ§-UIèŠçŽ ãšã®å¯Ÿè©±äžã«ããã¹ãã®ã³ãŒããçæãããŸãã
AppleãšAppiumã«ã¯ãã®ãããªããŒã«ããããŸãããCalaba.shã¯åºæ¬æ§æã«ã¯ãããŸãããããã®æ©èœãè³Œå ¥ã§ããXamarinã¯ã©ãŠãããããŸãã ãŸãããã¹ããå®è¡ã§ãã2,000ãè¶ ããããã€ã¹ãæäŸããŸãã ãã¹ãã®èšé²ã¯ãåžžã«éåžžã«è¯ããšã¯éããŸããã æã§äœãæžããªããšãäœãçæãããã®ãç解ã§ããªãããšããããŸãã ãã®ãããªããŒã«ããªãããšã¯ãã©ã¹ã«ãªããŸãã ããã«ã€ããŠã¯å°ãåŸã§èª¬æããŸãã
4.ãããžã§ã¯ãã®åã«ãããŒã ã®ã¡ã³ããŒãããŒã«ã䜿çšããçµéš ã
ç§ãã¡ã®ããŒã ã®å šå¡ã1ã€ã®ããŒã«ïŒAppleïŒã ãã䜿çšããŸããã ããæ£ç¢ºã«ã¯ã圌ãã¯åœŒã«ã€ããŠäœããç¥ã£ãŠããŸããã å šå¡ããã®ããŒã«ã«æºå ŽäžèŽã§æ祚ããŸããã ååãšããŠããããæäŸããæ©èœãæ¬ ããŠãããããä»ã®ãã©ãããã©ãŒã ã¯ããã»ã©éèŠã§ã¯ãããŸããã§ããã
圌ã«ã€ããŠããå°ãã話ãããŸãã
iOS Ulãã¹ãã¯ã2015幎ã«å°å ¥ãããããªãæ°ãããã¯ãããžãŒã§ãã 次ã®2ã€ã®ããšã«åºã¥ããŠããŸãã
- XCTest-ãã¹ããäœæããŠå®è¡ã§ãããã¬ãŒã ã¯ãŒã¯ã
- ã¢ã¯ã»ã·ããªãã£-é害ã®ãã人ãAppleããã€ã¹ãå®å
šã«äœ¿çšã§ããããã«ããŸãã UIãã¹ãã®å ŽåãUIãã¹ãã®å®è¡äžã«UIèŠçŽ ãšå¯Ÿè©±ããæ©èœãæäŸããŸãã
XCTestã¯3ã€ã®ã¯ã©ã¹ã®ã¿ã«åºã¥ããŠããŸãã
- XCUIã¢ããªã±ãŒã·ã§ã³-ã¢ããªã±ãŒã·ã§ã³ãšãã¹ãã®éã®äžçš®ã®ãããã·ã
- XCUIEIement-ç»é¢äžã®UIèŠçŽ ã
- XCUIEIementQuery-äœããã®åºæºã§ç»é¢äžã«ããèŠçŽ ãæ€çŽ¢ãããªã¯ãšã¹ãã
ãã¢UIãã¹ãã®èšé²
ããã¯ç°¡åã§ã-é¢æ°ã«ã«ãŒãœã«ã眮ããã¬ã³ãŒããã¯ãªãã¯ããŸãã UIãã¹ããéå§ãããŸãã èŠçŽ ãã¯ãªãã¯ãããšãã³ãŒããçæãããŸãã
圌ãçæãããã®ãèŠãŠã¿ãŸãããã
XCUIApplication *app = app2; [app.buttons[@"start"] tap]; XCUIElement *element = [[[[app.otherElements containingType:XCUIElementTypeNavigationBar identifier:@âUIViewâ] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element; [element tap]; XCUIApplication *app2 = app; [app2.keys[@"t"] tap]; [app typeText:@ât"]; . . . [app typeText:@"c"]; [app2.keys[@âo"] [element tap];
ãã¡ããã圌ã¯ãã€ãããã»ã©ã²ã©ãããšãããŠããããã§ã¯ãããŸããããç§ã¯æ£çŽã«ãã¢ã3ã4åé²é³ããããšããŸãããããã€ãåãééãã«ééããŸããã
- XCUIã¢ããªã±ãŒã·ã§ã³ã¯èª€ã£ãŠåæåããããã°ãšinitãäœæããŸããã§ãããã以åã¯å®çŸ©ãããŠããªãã£ãããã€ãã®ç¥è©±çãªå€æ°app2ãšåçã§ããã 次ã®ç»é¢ã§ã圌ã¯åãããšãããŸããã
- ã¢ã€ãã ãæ£ããèŠã€ãããŸããã§ããã èŠçŽ ã¯AccessibilityNotifierã«èšå®ãããŠããããããã®èŠçŽ ãæ€çŽ¢ããå¿
èŠããããŸããã ãããã圌ã¯ãããèŠããchildrenMatchingTypeãåçŽã«æ€çŽ¢ãå§ããŸããã
UIãã¹ãèšé²ã®çæïŒ
- å€ãã®ã³ãŒãã
- åžžã«èªã¿åãå¯èœãªã³ãŒãã§ã¯ãªã-å€ãã®
- åžžã«æ©èœããã³ãŒãã§ã¯ãããŸããã
- æ©èœã®åå©çšã¯å®è£ ãããŠããŸããã
UIãã¹ãã®èšé²ã®ãããã®æ¬ ç¹ã¯åžžã«èŠã€ãããšã¯éããŸããããUIãã¹ããäœæãããšãã¯é床ãéèŠã§ãã ãã°ãããçŸããããã€ãã®é¢æ°ãäœæãããã®ã§ãããåæã«ããã¹ãã¬ã³ãŒãã£ã³ã°ã®åŸã«æ»ã£ãŠäœããç·šéããããããŸããã ããã¯éåžžãèªåã§æžããããæéãããããŸãã
çè«ããå®è·µãž
æåã«ééããã®ã¯ã ã¹ã¿ããããŒãžã£ãŒã§ããã ãã以åã¯ããããžã§ã¯ãã«åäœãã¹ãã¯å®è£ ãããŠãããããããã¯ãŒã¯ãšã®éä¿¡ããšãã¥ã¬ãŒãããŠããŸããã§ããã
ãã¹ãèšé²ãšã©ãŒãç¹°ãè¿ããããã¹ããããã¯ãªãŒã³ã§æ£ç¢ºã«èšè¿°ããããšãéžæããŸããã Pageãªããžã§ã¯ããã¿ãŒã³ã¯ãããå©ããŠãããŸããã ããã«ã€ããŠç¥ã£ãŠãã人ã¯ã»ãšãã©ããŸãããããã¹ããæžããã¹ã¿ãŒã¯ç¥ã£ãŠããã¹ãã§ãã
UIãã¹ãã®å®è¡äžã«ã¹ã¯ãªãŒã³ã·ã§ãããæ®ãããã®ã¹ãããã·ã§ããããŒã«ãå®è£ ããŸããããã¹ãã®å®è¡æã«ã¯ã©ãã·ã¥ãããã©ããã確èªããã ãã§ãªããçµæã確èªããŠãç»é¢äžã®ãã¶ã€ã³ãæ¯èŒããŸããã
åé ç®ã詳现ã«æ€èšããŸãã
ã¹ã¿ããããŒãžã£ãŒ
äœããã®çç±ã§ããããã¯ãŒã¯ãšãã¥ã¬ãŒã·ã§ã³ã®å®è£ ã¯é£ãããšèããããŠããŸãã å®éããã¹ãŠã¯NSURLProtocolã¯ã©ã¹ã䜿çšããŠéåžžã«ç°¡åã«å®è¡ãããŸãã ããã¯ãiOSã®URLããŒãã£ã³ã°ã·ã¹ãã ã®åäœãäºåã«å®çŸ©ã§ããã¯ã©ã¹ã§ãã
ãã¹ãŠã¯2ã€ã®ã¢ã¯ã·ã§ã³ã§å®è¡ãããŸãã
- NSURLProtocolãç¶æ¿ããç¬èªã®ã¯ã©ã¹ãäœæããŸãã
- URLèªã¿èŸŒã¿ã·ã¹ãã ã«ç»é²ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã§ãããã¯ãŒã¯ã«ãªã¯ãšã¹ããéä¿¡ãããšãããŒãã·ã¹ãã ã¯ãŸãNSURLProtocolãç»é²ãããŠãããã©ããã確èªããŸãã ãããããªãã圌女ã¯èªåã®é çªã§ããããã«é Œãããã®ãªã¯ãšã¹ããåŠçããããšãå¯èœãã©ããå°ããŸãã ãã¯ãããšèšããšããããã¯ãŒã¯ãžã®ãªã¯ãšã¹ããçµäºããã¢ããªã±ãŒã·ã§ã³ã¬ãã«ã§åŠçãããŸãã
ã«ã¹ã¿ã ã¯ã©ã¹NSURLProtocol
åå®çŸ©ããå¿ èŠãããã®ã¯3ã€ã®ã¡ãœããã®ã¿ã§ãã
- ãã®ãªã¯ãšã¹ããåŠçã§ããŸããïŒtrueãŸãã¯falseãè¿ãã ãã§ãïŒïŒ
+(BOOL)canInitWithRequest:(NSURLRequest *)request
- startLoadingã¡ãœããèªäœãããŒã¿çœ®æã®ãã¹ãŠã®éæ³ãçºçããŸãã
-(void)startLoading
- æåŸã«ããªã¯ãšã¹ãã®åŠçãçµäºããããšãã·ã¹ãã ã«äŒããŸãã
-(void)stopLoading
ãã¹ãŠã®éæ³ãèµ·ããstartLoadingã«ã€ããŠããå°ãã
(void)startLoading NSData *cachedData if (cachedData) { NSHTTPURLResponse *response [self.client URLProtocol: didReceiveResponse: cacheStoragePolicy:]; [self.client URLProtocol:self didLoadData: cachedData]; [self.client URLProtocolDidFinishLoading: self]; } else { [self.client URLProtocol: self didFailWithError: }
å éšã§ã¯ããã£ãã·ã¥
(NSData *cachedData)
ããããŒã¿ãååŸããŸãã ç§ãã¡ã®å Žåããã¹ãã±ãŒã¹ããšã«åããªã¯ãšã¹ãã«å¯Ÿããç°ãªãåçãååšããå¯èœæ§ãããããããããã¯ç°ãªããã³ãã«ã«ä¿åãããŸãã ãã®ãããªããŒã¿ãããå Žåã¯ãç¬èªã®ã«ã¹ã¿ã å¿çãäœæããŠã·ã¹ãã ã«æž¡ãããã£ãã·ã¥ãããããŒã¿ãè¿ããšèšããŸãã
ãã®ããŒã¿ãèŠã€ãããªãã£ãå Žåã¯ãã«ã¹ã¿ã ãšã©ãŒãäœæããã ãã§ããããã¯ãŒã¯ããéä¿¡ãããããã«ãªã¯ãšã¹ãã«æ»ããŸãã
ã¹ã¿ããããŒãžã£ãŒã§ã¯ãã¯ã©ã¹ã®ã¿ãç»é²ããŸãã ããã¯ä»¥äžãä»ããŠè¡ãããŸãã
NSURLSessionConfiguration setProtocolClasses: @[[MyNSURLProtocol class]]
ãã¹ãŠãéåžžã«è¿ éãã€ç°¡åã«è¡ãããæ©èœããŸãã ã ãããããæããªãã§ãã ããã
ããŒãžãªããžã§ã¯ããã¿ãŒã³
ç§ãèšã£ãããã«ãç§ãã¡ã¯ãã¹ãèšé²ã®ãã€ãã¹é¢ãšæŠããUIãã¹ããæžãããã«ãã責任ããã¢ãããŒããåãããšã決ããŸããã ã³ãŒãããããã«ããããšããPageãªããžã§ã¯ããã¿ãŒã³ãé©çšããŸããã
ããã¯éåžžã«åçŽã§ããã¹ããšãã¹ããèšè¿°ãããç»é¢ã®éã«ãåå©çšãããæ©èœãå®è£ ãããŠããã¬ã€ã€ãŒãå¿ èŠã§ãããšããäºå®ã«åºã¥ããŠããŸãã ã€ãŸããèŠçŽ ãšã®ãã¹ãŠã®è€éãªçžäºäœçšãããã³ç»é¢äžã®èŠçŽ ã®ãã¹ãŠã®æ€çŽ¢ãããã§ä¿è·ãããŸãã
ããŒãžãªããžã§ã¯ããã¿ãŒã³ã®å©ç¹ïŒ
- ã³ãŒãã®èªã¿ãããã
- æ©èœã®åå©çšã
- ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ã€ã¹ã®äžå
åã
ç§ãã¡ã®ã¢ãããŒã
åç»é¢ã«ã¬ã€ã€ãŒãæžãã®ã¯äžèŠã ãšå€æããŸããã XCTestUtilsãšåŒã°ãã3ã€ã®ã³ã³ããŒãã³ãã§æ§æããããã¢ããªã±ãŒã·ã§ã³å šäœã®äžè¬çãªã¬ã€ã€ãŒã®ã¿ãäœæããŸããã
- ç»é¢äžã®ã¢ã€ãã ã®æ€çŽ¢ãä¿è·ãããFFElementsã¯ã©ã¹ã ããŒã«ããæ€çŽ¢ãšã€ã³ããã¯ã¹ã«ããæ€çŽ¢ã®2ã€ã®æ©èœãå®è£
ããŠããŸãã
@interface FFElements : NSObject -(XCUIElement *)objectForKeyedSubscript:(NSString *)key; -(XCUIElement *)objectAtIndexedSubscript:(NSUInteger)index; @end
- XCTestCaseã®ã«ããŽãªïŒèŠçŽ ïŒã ããã§ã¯ãUIãã¹ããèšè¿°ããããã«å¿
èŠãªç¹å®ã®FFElementã瀺ããŸãããã»ã«ãã©ãã«ããã¿ã³ã ããã¹ããã£ãŒã«ãã
@interface XCTestCase (Elements) @property (nonatomic,readonly) FFElements *textFields; @property (nonatomic,readonly) FFElements *buttons; @property (nonatomic,readonly) FFElements *labels; @property (nonatomic,readonly) FFElements *cells; -(void)wait:(NSTimeInterval)interval; @end
- textFieldsã®æäœã«åœ¹ç«ã€XCUIEIementã®å°ããªã«ããŽãªïŒ
@interface XCUIElement (Utils) @property (nonatomic) NSString *pasteText; +(void)forceTap; @end
ãã¢ã§èŠãããã«ãtextFieldsã«ããã¹ããå ¥åããããã«ãåãã¿ã³ãã¯ãªãã¯ããããã®ã³ãŒããçæãããŸãã forceTapæ©èœ-é·æŒããå°å ¥ããŸããã textFieldsãã¯ãªãã¯ãããšããPaste textããŸãã¯ãCopyãããã¯ã¹ã衚瀺ãããŸãã
ããã¯ã¯ãŒã«ã«ãªãã誰ãã幞ãã§ããã
ãã¢
Pageãªããžã§ã¯ããã¿ãŒã³ã®äœ¿çšæ¹æ³ã«é¢ããå°ããªãã¢ã瀺ããŸãã
ããããã£FFElementsãä»ããŠãç¹å®ã®ã¿ã€ãã®å ·è±¡èŠçŽ ã«ã¢ã¯ã»ã¹ããããããšå¯Ÿè©±ããã¡ãœãããåŒã³åºããŸãã textFieldsã¯æ¬¡ã®ããã«æäœããŸãïŒã¯ãªãã¯ããŠé·æŒãããããã¹ãã貌ãä»ããŸãã ãããããããèªã¿ãããããããŠæãéèŠãªã®ã¯ã6è¡ã ãã§ããã
ã¹ãããã·ã§ãã
UIãã¹ããå®è¡ããããã€ã¹äžã§å®è¡ããŸããããã¶ã€ã³ãããŸããããªãããšãããããŸãã ãããŠããããèŠãããšãã§ããŸãã
ãã®ãããã¹ãããã·ã§ããã®ãããªããŒã«ãå°å ¥ããããšã«ããŸããã ããã¯FastlaneããŒã«ã°ã«ãŒãã®äžéšã§ãããéåžžã«ã·ã³ãã«ã§å®è£ ãç°¡åã§ããã倧ããªã¡ãªããããããŸãã
ã¹ãããã·ã§ããã®å©ç¹ïŒ
- ã¹ã¯ãªãŒã³ã·ã§ãããæ®ããŸãã
- UIãã¹ããå®è¡ããé©åãªå Žæã§ã¹ã¯ãªãŒã³ã·ã§ãããæ®ããŸãã
- 端æ«ããå®è¡ããããããCIãšç°¡åã«çµ±åã§ããŸãã
ã¹ãããã·ã§ãããæåéãå®è£ ããã«ã¯ã3ã€ã®ã¹ããããå¿ èŠã§ãã
- ã¿ãŒããã«ã§ãfastlane snapshot initã³ãã³ããå
¥åããŸãã ãã®åŸãSnapfileãšãããã¡ã€ã«ãçæãããŸã-ãããæ§æãã¡ã€ã«ã§ãã
- Snapfileãæ§æããŸãã
- ã¹ã¯ãªãŒã³ã·ã§ãããååŸãããå Žæã瀺ããŸãã
ã¹ããããã¡ã€ã«
éåžžãUIãã¹ããå®è¡ãããã¹ãŠã®ããã€ã¹ãæå®ã§ããã¹ã¯ãªãŒã³ã·ã§ããã¯ç°ãªãããã€ã¹ã®åãå Žæã§æ®åœ±ãããŸãã
devices ([ "iPhone 6s" ]) scheme: "our scheme" output_directory: "./path/." stop_after_first_error: Bool reinstall_app: Bool clear_previous_screenshots: Bool Erase_simulator: Bool languages ([ "en-US" ])
ããã«ãUIãã¹ããå®è¡ããã¹ããŒã ããã¹ãŠã®ã¹ã¯ãªãŒã³ã·ã§ããã®çµæãä¿åããããã©ã«ããŒãããã³è£å©èšå®ã瀺ããŸãã
UIãã¹ããå®è¡ããèšèªãæå®ããããšãã§ããŸãã ããŒã«ã©ã€ãºçãå€æ°ããå Žåã¯ãããã§ãã¹ãŠã®ããŒã«ã©ã€ãºçãæå®ããåºåã§ç°ãªãèšèªã®ã¹ã¯ãªãŒã³ã·ã§ãããååŸã§ããŸãã
ã¹ã¯ãªãŒã³ã·ã§ããã®æé
æè¡çãªèŠ³ç¹ããã¯ãã³ãŒãèªäœã«ç¹å®ã®ãã¡ã€ã«-SnaphotHelperãè¿œå ããã ãã§ãã ãã¹ãã§ã¿ãŒã²ããã«è¿ éã«ã ãã®ãã¡ã€ã«ã¯ãããžã§ã¯ããã©ã«ããŒã«çæãããŸããfastlanesnapshot initãå®è¡ãããšãã¯ãã¿ãŒã²ããã«é 眮ããã ãã§ãã
次ã«ãã¹ã¯ãªãŒã³ã·ã§ãããæ®ããããã§XCUIã¢ããªã±ãŒã·ã§ã³ã転éãããã¹ãŠã®ãã¹ãã±ãŒã¹å ã§ã setupïŒïŒã¡ãœããå ã§[Snapshot setupSnapshotïŒapp]ãåŒã³åºããŸãã
æåŸã«æ®ã£ãŠããã®ã¯ãã¹ã¯ãªãŒã³ã·ã§ãããæ®ãããå Žæã§ã³ãŒããå®è¡ããåçãçæããã¹ã¯ãªãŒã³ã·ã§ããã®ååãæå®ããããšã§ã[ã¹ãããã·ã§ããã¹ãããã·ã§ããïŒ@ "Name screen" waitForLoadingIndicatorïŒYES] ãã¿ãŒããã«ããå®è¡ããfastlaneã¹ãããã·ã§ãããäœæããŠæºè¶³ããŸãã
ãã¹ãã«åæ Œãããšãç°ãªãç»é¢ã®åçã ãã§ãªããHTMLããŒãžãçæãããŸãã
ãã®äžã§ããã¹ãŠã®ç»åã¯ãããšãã°ãããã€ã¹ããšãããã³Snapfileã§æå®ããããŒã«ã©ã€ãºããšã«ãã«ããŽãªã«åé¡ãããŸãã 確ãã«ãå¯äžã®ãã€ãã¹ã¯ããããã®ãã¹ãŠã®ã¹ã¯ãªãŒã³ã·ã§ãããå®è¡ã®é åºã§ã¯ãªãååã§ãœãŒããããããšã§ãã
泚æããŠãã ããïŒ
UIãã¹ãã®å®è£ ã決å®ããåã«ãããã€ãã®ç¹ã«æ³šæããå¿ èŠããããŸãã
- ã¹ã¿ããããŒãžã£ãŒãæããå¿
èŠã¯ãããŸããã100ïŒ
å®è£
ããå¿
èŠããããŸãã å®éã®ãããã¯ãŒã¯ã§ã¯ããã¹ãã¯è¯ããããŸããã
- ããŒãžãªããžã§ã¯ããã¿ãŒã³ -ã³ãŒããUIãã¹ãçšã«äœæãããŠããå Žåã§ããã³ãŒãã®çŽåºŠã®ããã«æŠãå¿
èŠããããŸãã
- ã¹ãããã·ã§ããããŒã«ãç°¡åã«å®è£
ã§ããŸãã ãã¹ãŠã®ãã¹ãã±ãŒã¹ã®æºåãæŽã£ãŠããå Žåããã¹ãŠã®ã³ãŒããèšè¿°ãããŸããããã¯æ£åãŸã§ã«è¡ãããŸãã
ãã®ãããžã§ã¯ãã§ã¯ã次ã®å©ç¹ããããŸãã ã
- èšèšãã°ã®æ°ãã»ãŒãŒãã«æžãããŸããã
- ã¢ããªã±ãŒã·ã§ã³ã®ãã¹ãŠã®ã¹ã¯ãªãŒã³ã·ã§ãããè¿
éã«çæããããŒã«ãšãCIãšã®çµ±åãã¹ããå®è£
ããŸããã
- ã¢ããªã±ãŒã·ã§ã³ã§æ£ããã«ãŒãã£ã³ã°ã確èªããŸããã
ç§ã¯ããã«ã€ããŠã¯è©±ããŸããã§ããããããªãè€éãªã«ãŒãã£ã³ã°ããããŸãã åœã«ãã£ãŠç°ãªãå ŽåããããŸãã æ°ããç»é¢ããšã«ããã®ç»é¢ã®ã¿ã«ããç¹å®ã®èŠçŽ ããã§ãã¯ããŸããããããªãå Žåã¯ãééã£ãå Žæã«ãããäœããééã£ãŠããããšãæå³ããŸãã ãã®ãããã«ãŒãã£ã³ã°ã確èªããŸãã
ããããããã€ãçæããããŸããïŒ
- UIãã¹ãã®å®è£
æé ã åºæ¬çãªãã¬ãŒã ã¯ãŒã¯ãäœæããŸããPagââeãªããžã§ã¯ããã¿ãŒã³ãå®è£
ããSnapshotãStub Managerãå®è£
ããŸã-ããã¯éåžžã«è¿
éã«è¡ãããŸããããã¹ãã±ãŒã¹ãšãããã°ã®æ€èšã«æéãããããŸãã
- ãŸãããªãã¡ã¯ã¿ãªã³ã°æã«ãã¹ãããµããŒãããå¿
èŠããããŸãã ç§ãã¡ã®å Žåãããã¯éåžžã«é »ç¹ã«è¡ãããŸãã ãã¡ãããããã«è²»ããæéã¯ããŸããããŸããããå¿ããªãã§ãã ããã
çŽæã©ãããæåŸã«ãUIãã¹ããå®è£ ãã䟡å€ãããå Žåã«èããŸãã
䜿çšãã¹ãã¯äŸ¡å€ããããŸãïŒ
- é·æãããžã§ã¯ããããå Žå-100ïŒ
UIãã¹ããå®è£
ããå¿
èŠããããŸãã 補åã絶ããéçºããŠããå Žåã¯ãèšèšã®å質ã«ã責任ãè² ãå¿
èŠããããŸãã
- Pixel Perfectã«ã€ããŠå¯Ÿè©±ãè¡ãããäœããããã«è¡ããŸããããšããèšèã§ã¯ãªããã¢ããªã±ãŒã·ã§ã³å
šäœã®ã¹ã¯ãªãŒã³ã·ã§ãããæäŸããŠãä¿®æ£ãå¿
èŠãªãã®ã確èªã§ããããã«ããŸãã
- ã¢ããªã±ãŒã·ã§ã³ã«è€éãªããã²ãŒã·ã§ã³ããžãã¯ãããå Žåã¯ãUIãã¹ããå®è£
ããå¿
èŠããããŸããããã¯éåžžã«åœ¹ç«ã¡ãŸãã èšèšã«ããŸã泚æãæãããšããã§ããŸããããããã²ãŒã·ã§ã³ããã§ãã¯ããããã®ããžãã¯ã®å®è£
ã¯éåžžã«ç°¡åã§ãã
ãã¥ãŒã¹
ä»å¹Žãã¢ãã€ã«éçºã«é¢ããäŒè°ãå¥ã®ã€ãã³ãã«ç§»è¡ããããšã«ããŸãããAppsConfMoscowã¯å®å šã«å¥ã®ã€ãã³ãã«ãªãã10æ8æ¥ãš9æ¥ã«éå¬ãããŸãã ãã·ã¢æ倧ã®ã¢ãã€ã«éçºã€ãã³ããéå¬ããå šåœã®ãã¹ãŠã®ã¢ãã€ã«éçºè ã³ãã¥ããã£ãã掻å家ãéãã500人以äžã«60以äžã®ã¬ããŒããæ瀺ããäºå®ã§ãã
ãããã RIT ++ãã§ã¹ãã£ãã«ã§ã¯ãå€ãã®å€é¢çãªé¢é£ã¬ããŒãããããŸããããšãã°ã次ã®ã¢ããªã±ãŒã·ã§ã³ãåãåããŸããã
ã¢ãã€ã«DevOpsïŒã¢ãã€ã«éçºã®ããã»ã¹ãèªååããæ¹åããŸã / Vyacheslav ChernikovïŒBinwellïŒ
Mail.ru / Egor UtrobinïŒMail.ruïŒ ã®ããã³ããšã³ãã®ãã€ã¯ããµãŒãã¹
Scala / Yuri BadalyantsïŒ2GISïŒ ã§ã®ãã€ã¯ããµãŒãã¹ã®çµ±åãã¹ã
ãã ããPCã1ãæéåäœããã¢ããªã±ãŒã·ã§ã³ã®ãªã¹ãã調ã¹ãèå³ãããå Žåã¯ãã±ãããäºçŽããŸãã