KIF:如何自动运行/压力测试iOS应用发现一种罕见的UI错误的原因是什么? [英] KIF: How to auto-run/stress test an iOS app to find the cause of a rare UI bug?

查看:1130
本文介绍了KIF:如何自动运行/压力测试iOS应用发现一种罕见的UI错误的原因是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我加的 KIF 的的标题只为搜索索引puposes,考虑到大多数的答案竟然是讨论

Note: I added kif to the title just for search indexing puposes, considering that most of the answer turned out to discuss it

我在寻找类似的硒适用于iOS,基本上是一个测试自动化/单元测试框架,可以运行特定的UI场景很多很多次,直到它崩溃,这将帮我缩小的UI错误的原因是很少发生随机。

I'm looking for something like selenium for iOS, basically a test-automation/unit test framework that can run a certain UI scenario many many times until it crashes, which would help me narrow down the cause of a UI bug that happens very rarely and randomly.

(顺便说一句,我NSLogged数据源/表交互code的每一行,花时间分析潜在原因..但没有发现任何确凿..再次这个bug很少发生)。

(and by the way, I've NSLogged every single line of code of datasource/table interaction and spent hours analyzing the potential cause.. but found nothing conclusive.. again this bug very rarely happens).

我看了一些的<一个href=\"http://stackoverflow.com/questions/33207/what-is-the-best-way-to-unit-test-objective-c-$c$c\">unit在iOS中测试框架,但他们似乎是这么多。我不知道该挑。我也参考硒是基于推测,因为我已经与谁已经在过去使用中的硒大型网络项目的QA工作的乡亲(我假设必须有适用于iOS类似的东西)。

I looked at some of the unit testing frameworks in iOS, but they seem to be so many. I'm not sure which to pick. Also my reference to selenium is based on conjecture, as I've worked with QA folks who've used Selenium in large web projects in the past (and i'm assuming that there must be something similar for iOS).

现在我是一个人的球队在iOS项目的工作,我要去必须把QA帽子和输出图这个bug。

Now that I'm a one man team working on an iOS project, I'm gonna have to put a QA hat on and figure this bug out.

我现在面临一个经典的错误时,有插在一个UITableView行的实际数量和行的数据源委托申报的数量之间的差异出现这种情况。这是错误消息:

I'm facing a classic bug that happens when there is a discrepancy between the actual number of rows inserted in a UITableView and the number of rows that the datasource delegate returns. This is the error message:

*** Assertion failure in -[UITableView
 _endCellAnimationsWithContext:] Exception in insertRows: Invalid
 update: invalid number of rows in section 0.

The number of rows contained in an existing section after the update (2) must be equal to
 the number of rows contained in that section before the update (2),
 plus or minus the number of rows inserted or deleted from that section
 (1 inserted, 0 deleted) and plus or minus the number of rows moved
 into or out of that section (0 moved in, 0 moved out).

我点击一个的UITableViewCell 把我带到另一个的UITableView 。有时工作

I click on a UITableViewCell that takes me into another UITableView. Sometimes it works

有时(很少),它没有(上述错误):

and sometimes (very rarely) it doesn't (with the above error):

推荐答案

更新: ..我添加了例如code约2.0 KIF分处后下方。对于那些谁比具体的问题,我面对更感兴趣的是KIF:

update:.. i've added example code about KIF 2.0 at the bottom after divider.. for those who are more interested in KIF than the specific problem i'm facing:

在一些研究和试验。我已经收窄我的选择两个测试自动化库:
弗兰克并的 KIF 。我最终决定用 KIF 而借款黄瓜的小黄瓜的语法来形容我的单元测试。

After some research and experimenting.. I've narrowed down my options to two test-automation libraries: Frank and KIF. I ultimately decided to use KIF while borrowing cucumber's Gherkin syntax to describe my unit tests.

我选择的原因 KIF (而不是弗兰克)是 KIF 是一款基于100%的OBJ-C,而不是使用红宝石以及与弗兰克的情况。因此,建立更简单,而且它更适用于我的狭隘的测试用例要求。话虽这么说,我承认弗兰克会比较有用的,如果我的应用程序(使用intput从多个服务器等IE)是更为复杂。你可以看到这个优秀 presentation更多地了解KIF,弗兰克和其他自动化测试框架的优点和缺点,包括苹果自己的<一个href=\"http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UsingtheAutomationInstrument/UsingtheAutomationInstrument.html\"相对=nofollow> UI自动化。

The reason I chose KIF (rather than Frank) was that KIF is 100% obj-c based, rather than using ruby as well as was the case with Frank. So setting up is simpler, and it was more applicable to my narrow test case requirement. That being said, I admit Frank would be more useful if my application was more complicated (ie using intput from multiple servers etc). You can see the last quarter of this excellent presentation to learn more about the pros and cons of KIF, Frank and other automation-testing frameworks including Apple's own UI Automation.

使用KIF后,我发现的bug导致上述错误,我可以用它的KIF 100%的时间重现!为什么会发生如此罕见的原因是因为它发生,只有当我通过屏幕横置真快..和自KIF自动化的步骤..它在他们一个令人难以置信的速度快..这暴露了错误。)

所以,以下将是code我用于测试..这只是给你一个什么样KIF(和小黄瓜),能为你做一个快速的感觉的一个示例:

So following will be a sample of the code I used for testing.. this is just to give you a quick feel of what KIF (and Gherkin) can do for you:

在一个文件中我指定的场景我想运行:

in one file I specify the scenarios I want to run:

- (void)initializeScenarios;
{
    [self addScenario:[KIFTestScenario scenarioToCompleteSignInAndLoadInbox]];
    [self addScenario:[KIFTestScenario scenarioToFillAttachmentsWithData]];
    [self addScenario:[KIFTestScenario scenarioToViewAndLoadFileBucket]];
    [self addScenario:[KIFTestScenario scenarioToViewAndLoadFileBucketSubView]];
}

每个场景映射到步骤(了解更多关于小黄瓜语法 - 和行为驱动开发,这是基于测试驱动开发,我强烈建议阅读本约的黄瓜):

/* @given the application is at a fresh state
   @and   the user already has an imap email account with a valid username/pwd

   @then  the user can successfully log in
   @and   the inbox view will be loaded
   @and   the inbox will get loaded with the latest batch of emails in the user inbox
 */
+ (id)scenarioToCompleteSignInAndLoadInbox
{
    KIFTestScenario *scenario = 
      [KIFTestScenario scenarioWithDescription:@"Test that a user 
                                                 can successfully log in."];
    [scenario addStepsFromArray:[KIFTestStep stepsCompleteSignInAndLoadInbox]];

    return scenario;
}


/* @given that the user is already signed in
   @and   the user has already downloaded their folders 

   @then  the user can click on the folders view
   @and   the user can click on the 'attachments' remote folder
   @and   the latest batch from the 'attachments' remote folder will download
 */
+ (id)scenarioToFillAttachmentsWithData {
    KIFTestScenario* scenario = 
      [KIFTestScenario scenarioWithDescription:@"Test that we can view the 
                                                 attachments folder and fill 
                                                 it with data."];
    [scenario addStepsFromArray:[KIFTestStep stepsToFillAttachmentsWithData]];
    return scenario;

}

/* @given that the user is already signed in
   @and   the user has already downloaded their folders
   @and   the user has already downloaded attachments

   @then  the user can click on inbox menu button
   @and   the user can click on folder list menu button
   @and   the user can click on the file bucket icon (on the account list view)
   @and   the data for the file bucket is fetched from the dbase
   @and   the file bucket view displayes the attachments
 */
+ (id)scenarioToViewAndLoadFileBucket {
    KIFTestScenario *scenario = 
       [KIFTestScenario scenarioWithDescription:@"Test that a user can successfully 
                                                  view and load 
                                                  file bucket parent view"];
    [scenario addStepsFromArray:[KIFTestStep stepsToViewAndLoadFileBucketPage]];

    return scenario;
}

/* @given that the user is already signed in
   @and   the user has already downloaded their folders
   @and   the user has already downloaded attachments
   @and   the user has already opened file bucket view 

   @then  the user can click on a random row in the file bucket view table
   @and   the subview will retrieve data from the dbase pertaining to that row
   @and   the subview will display the data in the uitableview
 */
+ (id)scenarioToViewAndLoadFileBucketSubView {
    KIFTestScenario *scenario = 
       [KIFTestScenario scenarioWithDescription:@"Test that a user can successfully
                                                  view and load filet
                                                  bucket sub view"];
    [scenario addStepsFromArray:[KIFTestStep stepsToViewAndLoadFileBucketSubPage]];
    return scenario;   
}

和使用KIF的UI自动化的方法(这只是一个例子)中定义的步骤:

and steps are defined using KIF's UI automation methods (this is just one example):

// this step assumes there is an attachment folder that contains emails with attachments
+ (NSArray *)stepsToFillAttachmentsWithData {

    NSMutableArray* steps = [@[] mutableCopy];

    [steps addObject:
        [KIFTestStep stepToTapViewWithAccessibilityLabel:@"InboxMenuButton"]];

    NSIndexPath* indexPath = 
        [NSIndexPath indexPathForRow:remoteAttachmentFolderNumber inSection:0];
    KIFTestStep* tapAttachmentRowStep = 
        [KIFTestStep stepToTapRowInTableViewWithAccessibilityLabel:
                                     @"attachments" atIndexPath:indexPath];

    [steps addObject:[KIFTestStep stepToWaitForNotificationName:
         (NSString *)kBeganSyncingOlderEmails object:nil           
                          whileExecutingStep:tapAttachmentRowStep]];

    [steps addObject:tapAttachmentRowStep];

    [steps addObject:
        [KIFTestStep stepToWaitForViewWithAccessibilityLabel:@"attachments"]];

    KIFTestStep *fillingInboxStep = 
        [KIFTestStep stepToWaitForNotificationName:
                                 (NSString *)kOldMailBatchDelivered object:nil];

    [fillingInboxStep setTimeout:kSpecialTimeoutForLongTests];
    [steps addObject:fillingInboxStep];

    return steps;
}


KIF 2.0示例code:
KIF 2.0使用X code 5的所有新的测试导航 ..这是一个的巨大的比KIF 1.0所做的改进。现在您的测试感觉比过去多很多有机和天然。(即它会实时..而不是创建运行方案在未来等)..你甚至可以测试每一个与播放按钮等等。你应该尝试一下。


KIF 2.0 sample code: KIF 2.0 uses Xcode 5's all new test navigator.. which is a huge improvement than what KIF 1.0 was doing.. now your tests feel a lot more organic and natural than the past.. (ie it goes in real time.. rather than creating scenarios that run in the future etc).. you even get to test each one with a play button etc.. you should try it out.

下面是一些例子(再次使用小黄瓜语法):

here are some examples (again using gherkin syntax):

#import <KIF/KIF.h>
#import "KIFUITestActor+EXAdditions.h"
#import "KIFUITestActor+UserRegistration.h"

@interface LoginTests : KIFTestCase

@end
@implementation LoginTests

- (void)testReset {
    [tester flushDbase];
    [tester reset];
}

/* @given that the app is in a fresh clean state
 @and   that no one has ever registered with the server

 @then  the user can register their themselves with the server
 @and   immediately start with the rider's map
 @and   their location on the map shows
 */

- (void)testRegistration
{
    [tester flushDbase];
    [tester reset];
    [tester singleUserRegistration];
    [tester showUserCurrentLocationOnMap];
}

/* @given that the user has already registered with the server
   @and the user is not currently logged in

 @then  the user can login using their user name and password
 @and   immediately start with the rider's map
 @and   their location on the map shows
 */
- (void)testSuccessfulLogin
{
    [tester reset];
    [tester login];
    [tester showUserCurrentLocationOnMap];
}

/* @given that the user has already registered 
   @and that the user is already logged in before app launch

 @then the user starts on the map view with the location visible
 @and the button prompts them to set pick up location
 */
- (void)testStartOfApplication {
    [tester showUserCurrentLocationOnMap];
    [tester showsPickUpButton];
}
@end

下面是一些测试用例该种类的文件执行:

here is the implementation of some of the test cases in the category files:

- (void)reset
{
    [self runBlock:^KIFTestStepResult(NSError **error) {
        BOOL successfulReset = YES;

        // Do the actual reset for your app. Set successfulReset = NO if it fails.
        AppDelegate* appDelegate = [[UIApplication sharedApplication] delegate];
        [appDelegate resetApp];

        KIFTestCondition(successfulReset, error, @"Failed to reset some part of the application.");

        return KIFTestStepResultSuccess;
    }];
}

- (void)flushDbase {
    [self runBlock:^KIFTestStepResult(NSError **error){
        NSURL *url = [NSURL URLWithString:@"http://randomdomain.com/flush_db"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSError *connectionError = nil;

        BOOL databaseFlushSucceeded = YES;

        NSURLResponse *response;
        NSData *resultData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&connectionError];
        if (!resultData) {
            databaseFlushSucceeded = NO;
            KIFTestCondition(databaseFlushSucceeded, error, @"failed to connect to server!");
        }

        if (connectionError) {
            databaseFlushSucceeded = NO;
            KIFTestCondition(databaseFlushSucceeded, error, [NSString stringWithFormat:@"connection failed. Error: %@", [connectionError localizedDescription]]);
        }

        return KIFTestStepResultSuccess;
    }];
}


- (void)navigateToLoginPage
{
    [self tapViewWithAccessibilityLabel:@"login email"];
}

- (void)returnToLoggedOutHomeScreen
{
    [self tapViewWithAccessibilityLabel:@"Logout"];
    [self tapViewWithAccessibilityLabel:@"Logout"]; // Dismiss alert.
}

这篇关于KIF:如何自动运行/压力测试iOS应用发现一种罕见的UI错误的原因是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆