ǰÑÔ
Èç¹ûÓвâÊÔ´óÀз¢ÏÖÄÚÈݲ»¶Ô£¬»¶ÓÖ¸Õý£¬ÎһἰʱÐ޸ġ£
´ó¶àÊýµÄ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²âÊÔ£¬Óм¸¸öºËÐÄÀàÐèÒªÕÆÎÕ
- 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¡£ÒòΪËüÒÀÀµÓÚÍⲿ±äÁ¿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µÄ¿ªÔ´ÏîÄ¿£º
ÕâÊÇÒ»¸ö»ùÓÚxcodebuildÃüÁîµÄÀ©Õ¹£¬ÔÚiOS×Ô¶¯»¯²âÊԺͳÖÐø¼¯³ÉÁìÓòºÜÓÐÓÃ,¶øÇÒËüÖ§³Ö-parallelize²¢ÐвâÊÔ¶à¸öbundle£¬´ó´óÌá¸ß²âÊÔЧÂÊ¡£
°²×°XCTool,
ʹÓÃ
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 |