xperia usuario solucionar sistema sentimos responde problemas pantalla negra moto lollipop lamentablemente interfaz error detuvo con como aplicacion objective-c debugging automated-tests race-condition kif

objective-c - usuario - problemas con el iu



KIF: ¿Cómo ejecutar automáticamente/probar el estrés en una aplicación de iOS para encontrar la causa de un raro error de UI? (1)

Actualización: .. He agregado un código de ejemplo sobre KIF 2.0 en la parte inferior después del divisor ... para aquellos que están más interesados ​​en KIF que el problema específico que estoy enfrentando:

Después de algunas investigaciones y experimentos ... reduje mis opciones a dos bibliotecas de automatización de pruebas: Frank y KIF . Finalmente, decidí usar KIF al tomar prestada la sintaxis Gherkin de pepino para describir mis pruebas unitarias.

La razón por la que elegí KIF (en lugar de Frank ) fue que KIF está basado en el 100% obj-c, en lugar de usar ruby, así como en el caso de Frank . Por lo tanto, la configuración es más simple, y fue más aplicable a mi requisito de caso de prueba estrecha. Dicho esto, admito que Frank sería más útil si mi aplicación fuera más complicada (es decir, que usara la capacidad de entrada de varios servidores, etc.). Puede ver el último trimestre de esta excelente presentación para conocer más sobre los pros y los contras de KIF, Frank y otros marcos de prueba de automatización, incluida la propia Automatización de IU de Apple.

Después de usar KIF, encontré el error que causaba el error anterior, ¡y pude reproducirlo usando KIF el 100% del tiempo! La razón por la que ocurrió tan rara vez fue porque sucedió solo cuando hice tapping en las pantallas muy rápido ... y dado que KIF automatiza los pasos ... los hace a una velocidad increíblemente rápida ... lo que expuso el error :).

Entonces, lo siguiente será una muestra del código que utilicé para probar ... esto es solo para darle una idea rápida de lo que KIF (y Gherkin) pueden hacer por usted:

en un archivo especifico los escenarios que quiero ejecutar:

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

cada escenario se correlaciona con los pasos (para entender más sobre la sintaxis de pepinillo y el desarrollo impulsado por el comportamiento, que se basa en el desarrollo del controlador de prueba, recomiendo leer este excelente libro sobre el pepino ):

/* @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; }

y los pasos se definen utilizando los métodos de automatización de UI de KIF (este es solo un ejemplo):

// 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; }

Código de ejemplo de KIF 2.0: KIF 2.0 usa todo el nuevo navegador de prueba de Xcode 5 ... lo cual es una gran mejora de lo que KIF 1.0 estaba haciendo ... ahora sus pruebas se sienten mucho más orgánicas y naturales que en el pasado ... (es decir, va en la realidad tiempo ... en lugar de crear escenarios que se ejecutan en el futuro, etc.) ... incluso puedes probar cada uno con un botón de reproducción, etc. deberías probarlo.

aquí hay algunos ejemplos (nuevamente usando la sintaxis de pepinillo):

#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

aquí está la implementación de algunos de los casos de prueba en los archivos de categoría:

- (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. }

Nota: agregué kif al título solo para los temas de indexación de búsqueda, considerando que la mayoría de la respuesta resultó para discutirlo

Estoy buscando algo así como selenio para iOS, básicamente un marco de prueba de automatización / unidad que puede ejecutar un cierto escenario de IU muchas veces hasta que falla, lo que me ayudaría a reducir la causa de un error de IU que ocurre muy raramente y al azar.

(y, por cierto, he NSLogged cada línea de código de fuente de datos / interacción de tabla y pasé horas analizando la posible causa ... pero no encontré nada concluyente ... nuevamente, este error rara vez ocurre).

Miré algunos de los marcos de prueba de unidades en iOS , pero parecen ser tantos. No estoy seguro de qué elegir. También mi referencia al selenio se basa en conjeturas, ya que he trabajado con personas de QA que han usado Selenium en grandes proyectos web en el pasado (y supongo que debe haber algo similar para iOS).

Ahora que soy un equipo de un solo hombre que trabaja en un proyecto de iOS, voy a tener que poner un sombrero de control de calidad y resolver este error.

Me enfrenta a un error clásico que ocurre cuando hay una discrepancia entre el número real de filas insertadas en una UITableView y el número de filas que devuelve el delegado de la fuente de datos. Este es el mensaje de error:

*** 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).

Hago clic en una UITableViewCell que me lleva a otra UITableView . A veces funciona

y a veces (muy raramente) no (con el error anterior):