Äú¿ÉÒÔ¾èÖú£¬Ö§³ÖÎÒÃǵĹ«ÒæÊÂÒµ¡£

1Ôª 10Ôª 50Ôª





ÈÏÖ¤Â룺  ÑéÖ¤Âë,¿´²»Çå³þ?Çëµã»÷Ë¢ÐÂÑéÖ¤Âë ±ØÌî



  ÇóÖª ÎÄÕ ÎÄ¿â Lib ÊÓÆµ iPerson ¿Î³Ì ÈÏÖ¤ ×Éѯ ¹¤¾ß ½²×ù Model Center   Code  
»áÔ±   
   
 
     
   
 ¶©ÔÄ
  ¾èÖú
iOS×Ô¶¯»¯²âÊÔµÄÄÇЩ¸É»õ
 
À´Ô´£ºCocoachina ·¢²¼ÓÚ£º 2017-9-4
  4352  次浏览      35
 

ǰÑÔ

Èç¹ûÓвâÊÔ´óÀз¢ÏÖÄÚÈݲ»¶Ô£¬»¶Ó­Ö¸Õý£¬ÎһἰʱÐ޸ġ£

´ó¶àÊýµÄiOS App(ûÓгÖÐø¼¯³É)µü´úÁ÷³ÌÊÇÕâÑùµÄ

Ò²¾ÍÊÇ˵£¬²âÊÔÊÇ·¢²¼Ö®Ç°µÄ×îºóÒ»µÀ¹Ø¿¨¡£Èç¹ûbug²»ÄÜÔÚ²âÊÔÖз¢ÏÖ£¬ÄÇôbug¾Í»áµÖ´ïÓû§£¬ËùÒÔ²âÊÔµÄÍêÕûÐԺͿɿ¿ÐÔÊ®·ÖÖØÒª¡£

Ŀǰ£¬´ó¶àÊýApp»¹Í£ÁôÔÚÈ˹¤²âÊԽ׶Σ¬È˹¤²âÊÔͶÈëµÄ³É±¾×îµÍ£¬Äܹ»±£Ö¤ºËÐŦÄܵÄʹÓ㬶øÇÒ²âÊÔÈËÔ±²»ÐèÒª»áд´úÂë¡£

µ«ÊÇ£¬Ôںܶà²âÊÔ³¡¾°Ï£¬È˹¤²âÊÔµÄЧÂÊÌ«µÍ£¬ÈÝÒ׳ö´í¡£¾ÙÁ½¸ö³£¼ûµÄÀý×Ó£º

  • Ò»¸öAppµÄºËÐŦÄÜ£¬ÔÚÿһ´Î·¢²¼°æ±¾Ç°µÄ²âÊԱض¨»áÅÜÒ»±éËùÓеIJâÊÔÓÃÀý£¬²»¹Ü¶ÔÓ¦µÄÒµÎñÔÚµ±Ç°°æ±¾ÓÐûÓб仯£¨ÌìÖªµÀ¿ª·¢ÔÚ×öÒµÎñAµÄʱºò£¬¶ÔÒµÎñBÓÐûÓÐÓ°Ï죩£¬Èç¹ûÕâ´Î²â³öеÄbug£¬²âÊÔÈËÔ±ÔÚÏÂÒ»´Î·¢°æ²âÊÔÖУ¬ÓÖ²»µÃ²»×öÕâÐ©ÖØ¸´µÄ¹¤×÷¡£
  • ¿ª·¢ÔÚдAPIÇëÇóÏà¹Ø´úÂëµÄʱºòûÓÐ×öÊý¾ÝÈÝ´í£¬²âÊÔÔÚÈ˹¤²âÊÔµÄʱºò¶¼ÊÇÕý³£µÄÊý¾Ý£¬ËùÒÔ²âÊÔͨ¹ý¡£ÉÏÏßÁËÖ®ºó£¬ºǫ́ÅäÖÃÊý¾ÝµÄʱºò³öÁ˵ãСÎÊÌ⣬µ¼Ö´óÃæ»ý±ÀÀ££¬boom¡«¡£

È»ºó£¬Àϰå¾ÍÒª¹ýÀ´ÕÒÄãÁË

±¾ÎÄËù½²½âµÄ¾ùÊÇ»ùÓÚXCode 8.2.1£¬ÓÐЩ¸ÅÄî¿ÉÄܲ»ÊÊÓÃÓڵͰ汾µÄXCode

×Ô¶¯»¯²âÊÔ

×Ô¶¯»¯²âÊÔ¾ÍÊÇдһЩ²âÊÔ´úÂ룬ÓôúÂë´úÌæÈ˹¤È¥Íê³ÉÄ£¿éºÍÒµÎñµÄ²âÊÔ¡£

Æäʵ²»¹ÜÊÇ¿ª·¢»¹ÊDzâÊÔ£¬Èç¹ûÄãÔÚ²»¶ÏµÄ×öÖØ¸´ÐÔ¹¤×÷µÄʱºò£¬¾ÍÓ¦¸ÃÎÊ×Ô¼ºÒ»¸öÎÊÌ⣺ÊDz»ÊÇÓиü¸ßЧµÄ°ì·¨£¿

×Ô¶¯»¯²âÊÔÓкܶàÓŵ㣺

  • ²âÊÔËٶȿ죬±ÜÃâÖØ¸´ÐԵŤ×÷
  • ±ÜÃâregression£¬Èÿª·¢¸üÓÐÐÅÐÄÈ¥Ð޸ĺÍÖØ¹¹´úÂë(¸öÈËÈÏΪ×î´óµÄÓŵã)
  • ¾ßÓÐÒ»ÖÂÐÔ¡£
  • ÓÐÁË×Ô¶¯»¯²âÊÔ£¬³ÖÐø¼¯³É£¨CI£©»á±äµÃ¸ü¿É¿¿¡£
  • ÆÈʹ¿ª·¢ÈËԱд³ö¸ü¸ßÖÊÁ¿µÄ´úÂë¡££¨×Ô¶¯»¯²âÊÔ²»Í¨¹ý£¬´úÂë²»ÔÊÐíºÏ²¢£©

µ±È»£¬×Ô¶¯»¯²âÊÔÒ²ÓÐһЩȱµã¡£

  • ¿ª·¢ºÍά»¤³É±¾¸ß¡£
  • ²»ÄÜÍêÈ«Ìæ´úÈ˹¤²âÊÔ¡£
  • ÎÞ·¨ÍêÈ«±£Ö¤²âÊÔµÄ׼ȷÐÔ - ÈôúÂëÈ¥ÅжÏÒ»¶ÎÂß¼­ÊÇ·ñÕýÈ·ºÜÈÝÒ×£¬µ«ÊÇ£¬ÈôúÂëÅжÏÒ»¸ö¿Ø¼þÏÔʾÊÇ·ñÕýȷȴûÄÇôÈÝÒס£

ËùÒÔ£¬ÔÚ×ö×Ô¶¯»¯²âÊÔ֮ǰ£¬Ê×ÏÈÒªÎÊ×Ô¼º¼¸¸öÎÊÌ⣿

  • Õâ¸ö²âÊÔÒµÎñµÄ±ä¶¯ÊÇ·ñƵ·±£¿
  • Õâ¸ö²âÊÔÒµÎñÊÇ·ñÊôÓÚºËÐŦÄÜ£¿
  • ±àд²âÊÔ´úÂëµÄ³É±¾ÓжàÉÙ£¿
  • ×Ô¶¯»¯²âÊÔÄܱ£Ö¤²âÊÔ½á¹ûµÄ׼ȷô£¿

ͨ³££¬ÎÒÃÇ»áÑ¡ÔñÄÇЩҵÎñÎȶ¨£¬ÐèҪƵ·±²âÊԵIJ¿·ÖÀ´±àд×Ô¶¯»¯²âÊԽű¾£¬ÆäÓàµÄ²ÉÓÃÈ˹¤²âÊÔ£¬È˹¤²âÊÔÈÔÈ»ÊÇiOS App¿ª·¢Öв»¿ÉȱÉÙµÄÒ»²¿·Ö¡£

²âÊÔÖÖÀà

´ÓÊÇ·ñ½Ó´¥Ô´´úÂëµÄ½Ç¶ÈÀ´·ÖÀࣺ²âÊÔ·ÖΪºÚºÐºÍ°×ºÐ£¨»ÒºÐ¾ÍÊǺںа׺нáºÏ£¬ÕâÀï²»×öÌÖÂÛ£©¡£

°×ºÐ²âÊÔµÄʱºò£¬²âÊÔÈËÔ±ÊÇ¿ÉÒÔÖ±½Ó½Ó´¥´ý²âÊÔAppµÄÔ´´úÂëµÄ¡£°×ºÐ²âÊÔ¸ü¶àµÄÊǵ¥Ôª²âÊÔ£¬²âÊÔÈËÔ±Õë¶Ô¸÷¸öµ¥Ôª½øÐи÷ÖÖ¿ÉÄܵÄÊäÈë·ÖÎö£¬È»ºó²âÊÔÆäÊä³ö¡£°×ºÐ²âÊԵIJâÊÔ´úÂëͨ³£ÓÉiOS¿ª·¢±àд¡£

ºÚºÐ²âÊÔ¡£ºÚºÐ²âÊÔµÄʱºò£¬²âÊÔÈËÔ±²»ÐèÒª½Ó´¥Ô´´úÂë¡£ÊÇ´ÓApp²ãÃæ¶ÔÆäÐÐΪÒÔ¼°UIµÄÕýÈ·ÐÔ½øÐÐÑéÖ¤£¬ºÚºÐ²âÊÔÓÉiOS²âÊÔÍê³É¡£

´ÓÒµÎñµÄ²ã´ÎÉÏÀ´Ëµ£¬²âÊÔ½ð×ÖËþÈçͼ£º

¶øiOS²âÊÔͨ³£Ö»ÓÐÒÔÏÂÁ½¸ö²ã´Î£º

  • Unit£¬µ¥Ôª²âÊÔ£¬±£Ö¤Ã¿Ò»¸öÀàÄܹ»Õý³£¹¤×÷
  • UI£¬UI²âÊÔ£¬Ò²½Ð×ö¼¯³É²âÊÔ£¬´ÓÒµÎñ²ãµÄ½Ç¶È±£Ö¤¸÷¸öÒµÎñ¿ÉÒÔÕý³£¹¤×÷¡£

¿ò¼ÜÑ¡Ôñ

†ªÀï°ËིµÄÕâô¶à£¬×Ô¶¯»¯²âÊÔµÄЧÂÊÔõôÑù£¬¹Ø¼ü»¹ÊÇÔÚ²âÊÔ¿ò¼ÜÉÏ¡£ÄÇô£¬ÈçºÎÑ¡Ôñ²âÊÔ¿ò¼ÜÄØ£¿¿ò¼Ü¿ÉÒÔ·ÖΪÁ½´óÀࣺXCodeÄÚÖõĺÍÈý·½¿â¡£

Ñ¡Ôñ¿ò¼ÜµÄʱºòÓм¸¸ö·½ÃæÒª¿¼ÂÇ

  • ²âÊÔ´úÂë±àдµÄ³É±¾
  • ÊÇ·ñ¿Éµ÷ʽ
  • ¿ò¼ÜµÄÎȶ¨ÐÔ
  • ²âÊÔ±¨¸æ£¨½ØÍ¼£¬´úÂ븲¸ÇÂÊ£¬¡­£©
  • WebViewµÄÖ§³Ö£¨ºÜ¶àApp¶¼Óõ½ÁËH5£©
  • ×Ô¶¨Òå¿Ø¼þµÄ²âÊÔ
  • ÊÇ·ñÐèÒªÔ´´úÂë
  • ÄÜ·ñÐèÒªÁ¬×ŵçÄÔ
  • ÊÇ·ñÖ§³ÖCI£¨³ÖÐø¼¯³É£©
  • ¡­

ÎÒÃÇÊ×ÏÈÀ´¿´¿´XCodeÄÚÖõĿò¼Ü£ºXCTest¡£XCTestÓÖ¿ÉÒÔ·ÖΪÁ½²¿·Ö£ºUnit Test ºÍ UI Test£¬·Ö±ð¶ÔÓ¦µ¥Ôª²âÊÔºÍUI²âÊÔ¡£ÓÐһЩÈý·½µÄ²âÊÔ¿âÒ²ÊÇ»ùÓÚXCTest¿ò¼ÜµÄ£¬Õâ¸öÔÚºóÎĻὲµ½¡£ÓÉÓÚÊÇApple¹Ù·½ÌṩµÄ£¬ËùÒÔÕâ¸ö¿ò¼Ü»á²»¶ÏÍêÉÆ¡£

³ÉÊìµÄÈý·½¿ò¼Üͨ³£ÌṩÁ˺ܶà·â×°ºÃµÄÓкõĽӿڣ¬±ÊÕß×ۺ϶ԱÈÁËһЩ£¬ÍƼöÒÔÏ¿ò¼Ü£º

µ¥Ôª²âÊÔ£º

ÒÔÏÂÈý¸ö¿ò¼Ü¶¼ÊÇBDD(Behavior-driven development) - ÐÐΪÇý¶¯¿ª·¢¡£ÐÐΪÇý¶¯¿ª·¢¼òµ¥À´Ëµ¾ÍÊÇÏȶ¨ÒåÐÐΪ£¬È»ºó¶¨Òå²âÊÔÓÃÀý£¬½Ó×ÅÔÙ±àд´úÂë¡£ ʵ¼ùÖз¢ÏÖ£¬Í¨³£Ã»ÓÐÄÇô¶àʱ¼äÀ´Ïȶ¨ÒåÐÐΪ£¬²»¹ýBDDÖеÄdomain-specific language (DSL)Äܹ»ºÜºÃµÄÃèÊöÓÃÀýµÄÐÐΪ¡£

  • Kiwi ÀÏÅÆ²âÊÔ¿ò¼Ü
  • specta ÁíÒ»¸öBDDÓÅÐã¿ò¼Ü
  • Quick Èý¸öÏîÄ¿ÖÐStar×î¶à£¬Ö§³ÖOCºÍSwift£¬ÓÅÏÈÍÆ¼ö¡£

UI²âÊÔ

  • KIF »ùÓÚXCTestµÄ²âÊÔ¿ò¼Ü£¬µ÷ÓÃ˽ÓÐAPIÀ´¿ØÖÆUI£¬²âÊÔÓÃÀýÓÃObjective C»òSwift±àд¡£
  • appium »ùÓÚClient - ServerµÄ²âÊÔ¿ò¼Ü¡£AppÏ൱ÓÚÒ»¸öServer£¬²âÊÔ´úÂëÏ൱ÓÚClient£¬Í¨¹ý·¢ËÍJSONÀ´²Ù×÷APP£¬²âÊÔÓïÑÔ¿ÉÒÔÊÇÈÎÒâµÄ£¬Ö§³ÖandroidºÍiOS¡£

ƪ·ùÓÐÏÞ£¬±¾ÎÄ»áÏȽéÉÜXCtest£¬½Ó×ÅÈý·½µÄUnit¿ò¼Ü»áÒÔQuickΪÀý£¬UI Test¿ò¼Ü²àÖØ·ÖÎöKIF£¬appium½ö½ö×öÔ­Àí½²½â¡£

XCTest

¶ÔÓÚXCTestÀ´Ëµ£¬×îºóÉú³ÉµÄÊÇÒ»¸öbundle¡£bundleÊDz»ÄÜÖ±½ÓÖ´Ðе쬱ØÐëÒÀÀµÓÚÒ»¸öËÞÖ÷½ø³Ì¡£¹ØÓÚXCTest½øÐе¥Ôª²âÊԵĻù´¡(XCodeµÄʹÓã¬Òì²½²âÊÔ£¬ÐÔÄܲâÊÔ£¬´úÂ븲¸ÇÂʵÈ)£¬ÎÒÔÚÕâÆªÎÄÕÂÀï½²½â¹ý£¬ÕâÀï²»ÔÙÏêϸ½²½â¡£

iOS µ¥Ôª²âÊÔÖ®XCTestÏê½â

µ¥Ôª²âÊÔÓÃÀý

±ÈÈ磬ÎÒÓÐÒÔÏÂÒ»¸öº¯Êý£º

//ÑéÖ¤Ò»¶ÎTextÊÇ·ñÓÐЧ¡££¨²»ÄÜÒÔ¿Õ×Ö·û¿ªÍ·£¬²»ÄÜΪ¿Õ£©
- (BOOL)validText:(NSString *)text error:(NSError *__autoreleasing *)error{
}

ÄÇô£¬ÎÒ¸ÃÈçºÎΪÕâ¸öº¯Êý±àдµ¥Ôª²âÊԵĴúÂ룿ͨ³££¬ÐèÒª¿¼ÂÇÒÔÏÂÓÃÀý£º

  • ÊäÈëÒÔ¿Õ°××Ö·û»òÕß»»Ðзû¿ªÍ·µÄ£¬error²»Îª¿Õ£¬·µ»Ø NO
  • ÊäÈëÕýÈ·µÄÄÚÈÝ£¬errorΪ¿Õ£¬·µ»ØYES
  • ÊäÈëΪnil,error²»Îª¿Õ£¬·µ»Ø NO (±ß½çÌõ¼þ)
  • ÊäÈëΪ·ÇNSStringÀàÐÍ£¬ÑéÖ¤²»Í¨¹ý£¬·µ»ØNO £¨´íÎóÊäÈ룩
  • ÌØÊâÊäÈë×Ö·û£¨±êµã·ûºÅ£¬·ÇÓ¢Îĵȵȣ©

UI²âÊÔ

UI²âÊÔÊÇÄ£ÄâÓû§²Ù×÷£¬½ø¶ø´ÓÒµÎñ´¦²ãÃæ²âÊÔ¡£¹ØÓÚXCTestµÄUI²âÊÔ£¬½¨Òé¿´¿´WWDC 2015µÄÕâ¸öÊÓÆµ£º

  • UI Testing in Xcode

¹ØÓÚUI²âÊÔ£¬Óм¸¸öºËÐÄÀàÐèÒªÕÆÎÕ

  • XCUIApplication ²âÊÔÓ¦ÓõĴúÀí
  • XCUIElement Ò»¸öUIÉϿɼûµÄÊÓͼ¶ÔÏó
  • XCUIElementQuery ²éÕÒXCUIElement

UI²âÊÔ»¹ÓÐÒ»¸öºËÐŦÄÜÊÇUI Recording¡£Ñ¡ÖÐÒ»¸öUI²âÊÔÓÃÀý£¬È»ºóµã»÷ͼÖеÄСºìµã¼È¿ÉÒÔ¿ªÊ¼UI Recoding¡£Äã»á·¢ÏÖ£º

Ëæ×ŵã»÷Ä£ÄâÆ÷£¬×Ô¶¯ºÏ³ÉÁ˲âÊÔ´úÂë¡££¨Í¨³£×Ô¶¯ºÏ³É´úÂëºó£¬»¹ÐèÒªÊÖ¶¯µÄÈ¥µ÷Õû£©

ÔÚдUI²âÊÔÓÃÀýµÄʱºòҪעÒ⣺²âÊÔÐÐΪ¶ø²»ÊDzâÊÔ´úÂë¡£±ÈÈ磬ÎÒÃDzâÊÔÕâÑùÒ»¸öcase

½øÈëTodoÊ×Ò³£¬µã»÷add£¬½øÈëÌí¼ÓÒ³Ãæ£¬ÊäÈëÎÄ×Ö£¬µã»÷save¡£

²âÊÔЧ¹ûÈçÏ£º

¶ÔÓ¦²âÊÔ´úÂ룺

- (void)testAddNewItems{
//»ñÈ¡app´úÀí
XCUIApplication *app = [[XCUIApplication alloc] init];
//ÕÒµ½µÚÒ»¸ötabeview£¬¾ÍÊÇÎÒÃÇÏëÒªµÄtableview
XCUIElement * table = [app.tables elementBoundByIndex:0];
//¼Ç¼ÏÂÀ´Ìí¼Ó֮ǰµÄÊýÁ¿
NSInteger oldCount = table.cells.count;
//µã»÷Add
[app.navigationBars[@"ToDo"].buttons[@"Add"] tap];
//ÕÒµ½Textfield
XCUIElement *inputWhatYouWantTodoTextField = app.textFields[@"Input what you want todo"];
//µã»÷Textfield
[inputWhatYouWantTodoTextField tap];
//ÊäÈë×Ö·û
[inputWhatYouWantTodoTextField typeText:@"somethingtodo"];
//µã»÷±£´æ
[app.navigationBars[@"Add"].buttons[@"Save"] tap];
//»ñÈ¡µ±Ç°µÄÊýÁ¿
NSInteger newCount = table.cells.count;
//Èç¹ûcellsµÄÊýÁ¿¼ÓÒ»£¬ÔòÈÏΪ²âÊԳɹ¦
XCTAssert(newCount == oldCount + 1);
}

ÕâÀïÊÇͨ¹ýǰºótableviewµÄrowÊýÁ¿À´¶ÏÑԳɹ¦»òÕßʧ°Ü¡£

µÈ´ý

ͨ³££¬ÔÚÊÓͼÇл»µÄʱºòÓÐת³¡¶¯»­£¬ÎÒÃÇÐèÒªµÈ´ý¶¯»­½áÊø,È»ºó²ÅÄܼÌÐø£¬·ñÔòqueryµÄʱºòºÜ¿ÉÄÜÕÒ²»µ½ÎÒÃÇÏëÒªµÄ¿Ø¼þ¡£

±ÈÈ磬ÈçÏ´úÂëµÈ´ýVCת³¡½áÊø£¬µ±queryÖ»ÓÐÒ»¸ötableµÄʱºò£¬²Å¼ÌÐøÖ´ÐкóÐøµÄ´úÂë¡£

[self expectationForPredicate:[NSPredicate predicateWithFormat:@"self.count = 1"]
evaluatedWithObject:app.tables
handler:nil];
[self waitForExpectationsWithTimeout:2.0 handler:nil];
//ºóÐø´úÂë....

Tips: µ±ÄãµÄUI½á¹¹±È½Ï¸´ÔÓµÄʱºò£¬±ÈÈç¸÷ÖÖǶÌ×childViewController£¬Ê¹ÓÃXCUIElementQueryµÄ´úÂë»áºÜ³¤£¬Ò²²»ºÃά»¤¡£

ÁíÍ⣬UI²âÊÔ»¹»áÔÚÿһ²½²Ù×÷µÄʱºò½ØÍ¼£¬·½±ã¶Ô²âÊÔ±¨¸æ½øÐÐÑéÖ¤¡£

²é¿´²âÊÔ½á¹û

ʹÓûùÓÚXCTestµÄ¿ò¼Ü£¬¿ÉÒÔÔÚXCodeµÄreport navigatorÖв鿴²âÊÔ½á¹û¡£

ÆäÖУº

  • Tests ÓÃÀ´²é¿´ÏêϸµÄ²âÊÔ¹ý³Ì
  • Coverage ÓÃÀ´²é¿´´úÂ븲¸ÇÂÊ
  • Logs ÓÃÀ´²é¿´²âÊÔµÄÈÕÖ¾

µã»÷ͼÖеĺìÉ«¿òÖ¸ÏòµÄͼ±ê¿ÉÒÔ¿´µ½Ã¿Ò»²½UI²Ù×÷µÄ½ØÍ¼

³ýÁËÀûÓÃXCodeµÄGUI£¬»¹¿ÉÒÔͨ¹ýºóÎÄÌáµ½µÄÃüÁîÐй¤¾ßÀ´²âÊÔ£¬²é¿´½á¹û¡£

Stub/Mock

Ê×ÏȽâÊÍÁ½¸öÊõÓ

  • mock ±íʾһ¸öÄ£Äâ¶ÔÏó
  • stub ×·×Ù·½·¨µÄµ÷Óã¬ÔÚ·½·¨µ÷ÓõÄʱºò·µ»ØÖ¸¶¨µÄÖµ¡£

ͨ³££¬Èç¹ûÄã²ÉÓô¿´æµÄXCTest£¬ÍƼö²ÉÓÃOCMockÀ´ÊµÏÖmockºÍstub£¬µ¥Ôª²âÊÔµÄÈý·½¿âͨ³£ÒѼ¯³ÉÁËstubºÍmock¡£

ÄÇô£¬ÈçºÎʹÓÃmockÄØ£¿¾Ù¸ö¹Ù·½µÄÀý×Ó£º

//mockÒ»¸öNSUserDefaults¶ÔÏó
id userDefaultsMock = OCMClassMock( [NSUserDefaults class]);
//ÔÚµ÷ÓÃstringForKeyµÄʱºò£¬·µ»Øhttp://testurl
OCMStub([userDefaultsMock
stringForKey:@"MyAppURLKey"] ).andReturn( @"http://testurl");

ÔÙ±ÈÈ磬ÎÒÃÇÒª²âÊÔ´ò¿ªÆäËûApp£¬ÄÇôÈçºÎÅжÏȷʵ´ò¿ªÁËÆäËûAppÄØ£¿

id app = OCMClassMock([UIApplication class]);
OCMStub([app sharedInstance]).andReturn(app);
OCMVerify([app openURL:url]

ʹÓÃStub¿ÉÒÔÈÃÎÒÃǺܷ½±ãµÄʵÏÖÕâ¸ö¡£

¹ØÓÚOCMockµÄʹÓã¬ÍƼö¿´¿´objc.ioµÄÕâÆªÎÄÕÂ

  • Öû»²âÊÔ: Mock, Stub ºÍÆäËû

Quick

QuickÊǽ¨Á¢ÔÚXCTestSuiteÉϵĿò¼Ü£¬Ê¹ÓÃXCTestSuiteÔÊÐíÄ㶯̬´´½¨²âÊÔÓÃÀý¡£ËùÒÔ£¬Ê¹ÓÃQuick,ÄãÈÔÈÿÉÒÔʹÓÃXCodeµÄ²âÊÔÏà¹ØGUIºÍÃüÁîÐй¤¾ß¡£

ʹÓÃQuick±àдµÄ²âÊÔÓÃÀý¿´ÆðÀ´ÊÇÕâÑù×ӵģº

import Quick
import Nimble
class TableOfContentsSpec: QuickSpec {
override func spec() {
describe("the 'Documentation' directory") {
it("has everything you need to get started") {
let sections = Directory("Documentation").sections
expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups"))
expect(sections).to(contain("Installing Quick"))
}

context("if it doesn't have what you're looking for") {
it("needs to be updated") {
let you = You(awesome: true)
expect{you.submittedAnIssue}.toEventually(beTruthy())
}
}
}
}
}

BDDµÄ¿ò¼ÜÈòâÊÔÓÃÀýµÄÄ¿µÄ¸ü¼ÓÃ÷È·£¬²âÊÔÊÇ·ñͨ¹ý¸ü¼ÓÇåÎú¡£Ê¹ÓÃQuick,²âÊÔÓÃÀý·ÖΪÁ½ÖÖ£º

µ¥¶ÀµÄÓÃÀý - ʹÓÃitÀ´ÃèÊö

itÓÐÁ½¸ö²ÎÊý£¬

  • ÐÐΪÃèÊö
  • ÐÐΪµÄ²âÊÔ´úÂë

±ÈÈ磬ÒÔϲâÊÔDolphinÐÐΪ£¬Ëü¾ßÓÐÐÐΪis friendlyºÍis smart

//Swift´úÂë
class DolphinSpec: QuickSpec {
override func spec() {
it("is friendly") {
expect(Dolphin().isFriendly).to(beTruthy())
}

it("is smart") {
expect(Dolphin().isSmart).to(beTruthy())
}
}
}

¿ÉÒÔ¿´µ½£¬BDDµÄºËÐÄÊÇÐÐΪ¡£Ò²¾ÍÊÇ˵£¬ÐèÒª¹Ø×¢µÄÊÇÒ»¸öÀàÌṩÄÄЩÐÐΪ¡£

ÓÃÀý¼¯ºÏ£¬ÓÃdescribeºÍcontextÃèÊö

±ÈÈ磬ÑéÖ¤dolphinµÄclickÐÐΪµÄʱºò£¬ÎÒÃÇÐèÒªÁ½¸öÓÃÀý¡£Ò»¸öÊÇis loud,Ò»¸öÊÇhas a high frequency£¬¾Í¿ÉÒÔÓÃdescribe½«ÓÃÀý×éÖ¯ÆðÀ´¡£

class DolphinSpec: QuickSpec {
override func spec() {
describe("a dolphin") {
describe("its click") {
it("is loud") {
let click = Dolphin().click()
expect(click.isLoud).to(beTruthy())
}

it("has a high frequency") {
let click = Dolphin().click()
expect(click.hasHighFrequency).to(beTruthy())
}
}
}
}
}

context¿ÉÒÔÖ¸¶¨ÓÃÀýµÄÌõ¼þ£º

±ÈÈç

describe("its click") {
context("when the dolphin is not near anything interesting") {
it("is only emitted once") {
expect(dolphin!.click().count).to(equal(1))
}
}
}

³ýÁËÕâЩ֮Í⣬QuickÒ²Ö§³ÖһЩÇÐÈëµã£¬½øÐвâÊÔǰµÄÅäÖãº

  • beforeEach
  • afterEach
  • beforeAll
  • afterAll
  • beforeSuite
  • afterSuite
  • Nimble

ÓÉÓÚQuickÊÇ»ùÓÚXCTest£¬¿ª·¢Õßµ±È»¿ÉÒÔÊÕʹÓöÏÑÔÀ´¶¨Òå²âÊÔÓÃÀý³É¹¦»òÕßʧ°Ü¡£QuickÌṩÁËÒ»¸ö¸üÓкõÄFrameworkÀ´½øÐÐÕâÖÖ¶ÏÑÔ£ºNimble

±ÈÈ磬һ¸ö³£¼ûµÄXCTest¶ÏÑÔÈçÏ£º

XCTAssertTrue(ConditionCode, "FailReason")11

ÔÚ³ö´íµÄʱºò£¬»áÌáʾ

XCAssertTrue failed, balabala

Õâʱºò£¬¿ª·¢ÕßÒª´ò¸ö¶Ïµã£¬²é¿´ÏÂÉÏÏÂÎÄ£¬¿´¿´¾ßÌåʧ°ÜµÄÔ­ÒòÔÚÄÄ¡£

ʹÓÃNimbleºó£¬¶ÏÑÔ±ä³ÉÀàËÆ

expect(1 + 1).to(equal(2))
expect(3) > 2
expect("seahorse").to(contain("sea"))
expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi"))

²¢ÇÒ£¬³ö´íµÄʱºò£¬ÌáʾÐÅÏ¢»á´ø×ÅÉÏÏÂÎĵÄÖµÐÅÏ¢£¬Èÿª·¢Õ߸üÈÝÒ×µÄÕÒµ½´íÎó¡£

ÈÃÄãµÄ´úÂë¸üÈÝÒ×µ¥Ôª²âÊÔ

²âÊÔµÄ׼ȷÐԺ͹¤×÷Á¿ºÜ´ó³Ì¶ÈÉÏÒÀÀµÓÚ¿ª·¢ÈËÔ±µÄ´úÂëÖÊÁ¿¡£

ͨ³££¬ÎªÁ˵¥Ôª²âÊÔµÄ׼ȷÐÔ£¬ÎÒÃÇÔÚдº¯Êý(·½·¨)µÄʱºò»á½è¼øÒ»Ð©º¯Êýʽ±à³ÌµÄ˼Ïë¡£ÆäÖÐ×îÖØÒªµÄÒ»¸ö˼Ïë¾ÍÊÇ

  • pure function(´¿º¯Êý)

ºÎΪPure function£¿¾ÍÊÇÈç¹ûÒ»¸öº¯ÊýµÄÊäÈëÒ»Ñù£¬ÄÇôÊä³öÒ»¶¨Ò»Ñù¡£

±ÈÈ磬ÕâÑùµÄÒ»¸öº¯Êý¾Í²»ÊÇpure function¡£ÒòΪËüÒÀÀµÓÚÍⲿ±äÁ¿valueµÄÖµ¡£

static NSInteger value = 0;
- (NSInteger)function_1{
value = value + 1;
return value;
}

¶øÕâ¸öº¯Êý¾ÍÊÇpure function£¬ÒòΪ¸ø¶¨ÊäÈ룬Êä³öÒ»¶¨Ò»Ö¡£

- (NSInteger)function_2:(NSInteger)base{
NSInteger value = base + 1;
return value;
}

ËùÒÔ£¬Èç¹ûÄãдÁËÒ»¸öûÓвÎÊý£¬»òÕßûÓзµ»ØÖµµÄ·½·¨£¬ÄÇôÄãҪСÐÄÁË£¬ºÜ¿ÉÄÜÕâ¸ö·½·¨ºÜÄѲâÊÔ¡£

¹ØÓÚMVC

ÔÚÁ¼ºÃµÄMVC¼Ü¹¹µÄAppÖУ¬

  • ViewÖ»×ö´¿´âµÄչʾÐ͹¤×÷£¬°ÑÓû§½»»¥Í¨¹ý¸÷ÖÖ·½Ê½´«µÝµ½Íⲿ
  • ModelÖ»×öÊý¾Ý´æ´¢À๤×÷
  • Controller×÷ΪViewºÍModelµÄÊàŦ£¬ÍùÍùÒªºÍºÜ¶àViewºÍModel½øÐн»»¥£¬Ò²ÊÇ×Ô¶¯»¯°üÀ¨´úÂëά»¤µÄÍ´µã¡£

ËùÒÔ£¬¶ÔControllerÊÝÉíÊÇiOS¼Ü¹¹ÖбȽÏÖØÒªµÄÒ»»·£¬Ò»Ð©Í¨Óõļ¼ÇɰüÀ¨£º

Âß¼­³éÀ룺

  • ÍøÂçÇëÇó¶ÀÁ¢¡£¿ÉÒÔÿ¸öÍøÂçÇëÇóÒÔCommandģʽ·â×°³ÉÒ»¸ö¶ÔÏ󣬲»ÒªÖ±½ÓÔÚControllerµ÷ÓÃAFNetworking¡£
  • Êý¾Ý´æ´¢¶ÀÁ¢¡£½¨Á¢¶ÀÁ¢µÄStoreÀ࣬ÓÃÀ´×öÊý¾Ý³Ö¾Ã»¯ºÍ»º´æ¡£
  • ¹²ÓÐÊý¾Ý·þÎñ»¯£¨Ð­Ò飩¡£±ÈÈçµÇ¼״̬µÈµÈ£¬Í¨¹ý·þÎñÈ¥·ÃÎÊ£¬ÕâÑù·þÎñÌṩÕßÖ®ÐèÒª´¦Àí·þÎñµÄÖÊÁ¿£¬·þÎñʹÓÃÕßÔòÐÅÈηþÎñÌṩÕߵĽá¹û¡£

ControllerÓëView½âñîºÏ

  • ½¨Á¢ViewModel²ã£¬ÕâÑùControllerÖ»ÐèÒªºÍViewModel½øÐн»»¥¡£
  • ½¨Á¢UIView×ÓÀà×÷ΪÈÝÆ÷£¬½«Ò»Ð©View·Åµ½ÈÝÆ÷ºóÔÙ°ÑÈÝÆ÷×÷ΪSubViewÌí¼Óµ½ControllerÀï
  • ½¨Á¢¿É¸´ÓõÄLayout²ã£¬²»¹ÜÊÇAutoLayout»¹ÊÇÊÖ¶¯²¼¾Ö¡£

ControllerÓëController½âñîºÏ

  • ½¨Á¢Ò³ÃæÂ·ÓÉ¡£Ã¿Ò»¸ö½çÃæ¶¼³éÏóΪһ¸öURL£¬Ìø×ª½ö½öͨ¹ýIntent»òÕßURLÌø×ª£¬ÕâÑùÁ½¸öControllerÍêÈ«¶ÀÁ¢¡£

Èç¹ûÄãµÄAppÓÃSwift¿ª·¢£¬ÄÇ̫̾ÏòЭÒé±à³ÌºÍ²»¿É±äµÄÖµÀàÐÍ»áÈÃÄãµÄ´úÂë¸üÈÝÒײâÊÔ¡£

µ±È»£¬iOS×齨»¯¶Ô×Ô¶¯»¯²âÊԵİïÖúÒ²ºÜ´ó£¬ÒòΪ²»¹ÜÊÇ»ù´¡×é¼þ»¹ÊÇÒµÎñ×é¼þ£¬¶¼¿ÉÒÔ¶ÀÁ¢²âÊÔ¡£×齨»¯ÓÖÊÇÒ»¸öºÜ´óµÄ¿ÎÌ⣬ÕâÀï²»ÉîÈë½²½âÁË¡£

KIF

KIFµÄÈ«³ÆÊÇKeep it functional¡£ËüÊÇÒ»¸ö½¨Á¢ÔÚXCTestµÄUI²âÊÔ¿ò¼Ü£¬Í¨¹ýaccessibilityÀ´¶¨Î»¾ßÌåµÄ¿Ø¼þ£¬ÔÙÀûÓÃ˽ÓеÄAPIÀ´²Ù×÷UI¡£ÓÉÓÚÊǽ¨Á¢ÔÚXCTestÉϵģ¬ËùÒÔÄã¿ÉÒÔÍêÃÀµÄ½èÖúXCodeµÄ²âÊÔÏà¹Ø¹¤¾ß£¨°üÀ¨ÃüÁîÐнű¾£©¡£

> KIFÊǸöÈ˷dz£ÍƼöµÄÒ»¸ö¿ò¼Ü£¬¼òµ¥Ò×Óá£

ʹÓÃKIF¿ò¼ÜÇ¿ÖÆÒªÇóÄãµÄ´úÂëÖ§³Öaccessibility¡£Èç¹ûÄã֮ǰû½Ó´¥¹ý£¬¿ÉÒÔ¿´¿´AppleµÄÎĵµ

  • Accessibility Programming Guide for iOS

¼òµ¥À´Ëµ£¬accessibilityÄܹ»ÈÃÊÓ¾õÕϰ­ÈËʿʹÓÃÄãµÄApp¡£Ã¿Ò»¸ö¿Ø¼þ¶¼ÓÐÒ»¸öÃèÊöAccessibilityLabel¡£ÔÚ¿ªÆôVoiceOverµÄʱºò£¬µã»÷¿Ø¼þ¾Í¿ÉÒÔÑ¡Öв¢ÇÒÌýµ½¶ÔÓ¦µÄÃèÊö¡£

ͨ³£UIKitµÄ¿Ø¼þÊÇÖ§³ÖaccessibilityµÄ£¬×Ô¶¨¶¨Òå¿Ø¼þ¿ÉÒÔͨ¹ý´úÂë»òÕßStoryboardÉÏÉèÖá£

ÔÚStoryboardÉÏÉèÖãº

  • ÉÏÃæµÄͨ¹ýRuntime AttributesÉèÖã¨KVC£©
  • ÏÂÃæµÄͨ¹ýGUIÀ´ÉèÖÃ

ͨ¹ý´úÂëÉèÖãº

[alert setAccessibilityLabel:@"Label"];
[alert setAccessibilityValue:@"Value"];
[alert setAccessibilityTraits:UIAccessibilityTraitButton];

Èç¹ûÄãÓÐЩAccessibilityµÄ¾­Ñ飬ÄÇôÄã¿Ï¶¨ÖªµÀ£¬ÏñTableViewµÄÕâÖÖ²»Ó¦¸ÃÖ§³ÖVoiceOverµÄ¡£ÎÒÃÇ¿ÉÒÔÓÃÌõ¼þ±àÒëÀ´Ö»¶Ô²âÊÔTarget½øÐÐÉèÖãº

#ifdef DEBUG
[tableView setAccessibilityValue:@"Main List Table"];
#endif
#ifdef KIF_TARGET (Õâ¸öÖµÐèÒªÔÚbuild settingsÀïÉèÖÃ)
[tableView setAccessibilityValue:@"Main List Table"];
#endif

ʹÓÃKIFÖ÷ÒªÓÐÁ½¸öºËÐÄÀࣺ

  • KIFTestCase XCTestCaseµÄ×ÓÀà
  • KIFUITestActor ¿ØÖÆUI£¬³£¼ûµÄÈýÖÖÊÇ£ºµã»÷Ò»¸öView£¬ÏòÒ»¸öViewÊäÈëÄÚÈÝ£¬µÈ´ýÒ»¸öViewµÄ³öÏÖ

ÎÒÃÇÓÃKIFÀ´²âÊÔÌí¼ÓÒ»¸öеÄToDo

- (void)testAddANewItem{
[tester tapViewWithAccessibilityLabel:@"Add"];
[tester enterText:@"Create a test to do item" intoViewWithAccessibilityLabel:@"Input what you want todo"];
[tester tapViewWithAccessibilityLabel:@"Save"];
[tester waitForTimeInterval:0.2];
[tester waitForViewWithAccessibilityLabel:@"Create a test to do item"];
}

ÃüÁîÐÐ

×Ô¶¯»¯²âÊÔÖУ¬ÃüÁîÐй¤¾ß¿ÉÒÔfacebookµÄ¿ªÔ´ÏîÄ¿£º

  • xctool

ÕâÊÇÒ»¸ö»ùÓÚxcodebuildÃüÁîµÄÀ©Õ¹£¬ÔÚiOS×Ô¶¯»¯²âÊԺͳÖÐø¼¯³ÉÁìÓòºÜÓÐÓÃ,¶øÇÒËüÖ§³Ö-parallelize²¢ÐвâÊÔ¶à¸öbundle£¬´ó´óÌá¸ß²âÊÔЧÂÊ¡£

°²×°XCTool,

brew install xctool11

ʹÓÃ

path/to/xctool.sh \
-workspace YourWorkspace.xcworkspace \
-scheme YourScheme \
-reporter plain:/path/to/plain-output.txt \
run-test

²¢ÇÒ£¬xctool¶ÔÓÚ³ÖÐø¼¯³ÉºÜÓÐÓã¬iOS³£ÓõijÖÐø¼¯³ÉµÄserverÓÐÁ½¸ö£º

  • Travis CI ¶ÔÓÚ¹«¿ª²Ö¿â£¨±ÈÈçgithub£©Ãâ·Ñ£¬Ë½ÓвֿâÊÕ·Ñ
  • Jenkins Ãâ·Ñ

ÓÅ»¯ÄãµÄ²âÊÔ´úÂë

׼ȷµÄ²âÊÔÓÃÀý

ͨ³££¬ÄãµÄÄãµÄ²âÊÔÓÃÀý·ÖΪÈý²¿·Ö£º

  • ÅäÖòâÊԵijõʼ״̬
  • ¶ÔÒª²âÊÔµÄÄ¿±êÖ´ÐдúÂë
  • ¶Ô²âÊÔ½á¹û½øÐжÏÑÔ£¨³É¹¦ or ʧ°Ü£©

²âÊÔ´úÂë½á¹¹

µ±²âÊÔÓÃÀý¶àÁË£¬Äã»á·¢ÏÖ²âÊÔ´úÂë±àдºÍά»¤Ò²ÊÇÒ»¸ö¼¼Êõ»î¡£Í¨³££¬ÎÒÃÇ»á´Ó¼¸¸ö½Ç¶È¿¼ÂÇ£º

  • ²»Òª²âÊÔ˽Óз½·¨£¨·â×°ÊÇOOPµÄºËÐÄ˼ÏëÖ®Ò»£¬²»ÒªÎªÁ˲âÊÔÆÆ»µ·â×°£©
  • ¶ÔÓÃÀý·Ö×飨¹¦ÄÜ£¬ÒµÎñÏàËÆ£©
  • ¶Ôµ¥¸öÓÃÀý±£Ö¤²âÊÔ¶ÀÁ¢£¨²»ÊÜ֮ǰ²âÊÔµÄÓ°Ï죬²»Ó°ÏìÖ®ºóµÄ²âÊÔ£©£¬ÕâÒ²ÊDzâÊÔÊÇ·ñ׼ȷµÄºËÐÄ¡£
  • ÌáÈ¡¹«¹²µÄ´úÂëºÍ²Ù×÷£¬¼õÉÙcopy/pasteÕâÀ๤×÷£¬²âÊÔÓÃÀýÊÇÉϲãµ÷Óã¬Ö»¹ØÐÄÒµÎñÂß¼­£¬²»¹ØÐÄÄÚ²¿´úÂëʵÏÖ¡£

Ò»¸ö³£¼ûµÄ²âÊÔ´úÂë×éÖ¯ÈçÏ£º

appium

appium²ÉÓÃÁËClient ServerµÄģʽ¡£¶ÔÓÚAppÀ´Ëµ¾ÍÊÇÒ»¸öServer£¬»ùÓÚWebDriver JSON wire protocol¶Ôʵ¼ÊµÄUI²Ù×÷¿â½øÐÐÁË·â×°£¬²¢ÇÒ±©Â¶³öRESTFULµÄ½Ó¿Ú¡£È»ºó²âÊÔ´úÂëͨ¹ýHTTPÇëÇóµÄ·½Ê½£¬À´½øÐÐʵ¼ÊµÄ²âÊÔ¡£ÆäÖУ¬Êµ¼ÊÇý¶¯UIµÄ¿ò¼Ü¸ù¾Ýϵͳ°æ±¾ÓÐËù²»Í¬£º

  • < 9.3 ²ÉÓÃUIAutomation
  • >= 9.3 XCUITest

Ô­ÒòÒ²±È½Ï¼òµ¥£ºAppleÔÚ10.0Ö®ºó£¬ÒƳýÁËUIAutomationµÄÖ§³Ö£¬Ö»Ö§³ÖXCUITest¡£

¶Ô±ÈKIF£¬appiumÓÐËüµÄÓŵ㣺

  • ¿çƽ̨£¬Ö§³ÖiOS£¬Android
  • ²âÊÔ´úÂë¿ÉÒÔÓɶàÖÖÓïÑÔ±àд£¬Õâ¶Ô²âÊÔÀ´ËµÃż÷¸üµÍ
  • ²âÊԽű¾¶ÀÁ¢ÓëÔ´´úÂëºÍ²âÊÔ¿ò¼Ü

µ±È»£¬Èκοò¼Ü¶¼ÓÐȱµã£º

  • ×Ô¶¨Òå¿Ø¼þÖ§³Ö²»ºÃ
  • WebViewµÄÖ§³Ö²»ºÃ

×ܽá

ÓÉÓÚÎÒ²»ÊÇרҵµÄiOS²âÊÔ£¬¹ØÓÚ²âÊÔµÄÒ»µã¼û½âÈçÏ£º

µ¥Ôª²âÊÔ»¹ÊÇÑ¡ÔñBDD¿ò¼Ü£¬±Ï¾¹¿É¶ÁÐÔ¸ßһЩ£¬ÍƼöQuick£¨Swift£©£¬Kiwi(Objective C)

UI²âÊÔÓÅÏÈÍÆ¼öKIF£¬Èç¹ûÐèÒª¼æ¹Ë°²×¿²âÊÔ£¬»òÕß²âÊÔÈËÔ±¶ÔOC/SwiftºÜİÉú£¬¿ÉÒÔ²ÉÓÃappium

   
4352 ´Îä¯ÀÀ       35
Ïà¹ØÎÄÕÂ

΢·þÎñ²âÊÔÖ®µ¥Ôª²âÊÔ
һƪͼÎÄ´øÄãÁ˽â°×ºÐ²âÊÔÓÃÀýÉè¼Æ·½·¨
È«ÃæµÄÖÊÁ¿±£ÕÏÌåϵ֮»Ø¹é²âÊÔ²ßÂÔ
È˹¤ÖÇÄÜ×Ô¶¯»¯²âÊÔ̽Ë÷
Ïà¹ØÎĵµ

×Ô¶¯»¯½Ó¿Ú²âÊÔʵ¼ù֮·
jenkins³ÖÐø¼¯³É²âÊÔ
ÐÔÄܲâÊÔÕï¶Ï·ÖÎöÓëÓÅ»¯
ÐÔÄܲâÊÔʵÀý
Ïà¹Ø¿Î³Ì

³ÖÐø¼¯³É²âÊÔ×î¼Ñʵ¼ù
×Ô¶¯»¯²âÊÔÌåϵ½¨ÉèÓë×î¼Ñʵ¼ù
²âÊԼܹ¹µÄ¹¹½¨ÓëÓ¦ÓÃʵ¼ù
DevOpsʱ´úµÄ²âÊÔ¼¼ÊõÓë×î¼Ñʵ¼ù