iphone ios testing ocunit first-responder

iphone - Prueba de la unidad iOS: ¿Cómo configurar/actualizar/examinar firstResponder?



testing ocunit (3)

¿Cómo se escriben las primeras pruebas unitarias de respuesta?

Estoy intentando escribir una prueba para confirmar que un método avanza el enfoque al siguiente campo de texto. controller es un descendiente de UIViewController . Pero esta prueba exploratoria falla:

- (void)testFirstResponder { [controller view]; [[controller firstTextField] becomeFirstResponder]; STAssertTrue([[controller firstTextField] isFirstResponder], nil); }

La primera línea hace que la vista se cargue de modo que sus salidas estén en su lugar. Los campos de texto son nulos. Pero la prueba nunca pasa.

Supongo que becomeFirstResponder no configura el primer respondedor de inmediato, pero lo programa para más adelante. Entonces, ¿hay una buena manera de escribir una prueba de unidad contra ella?

Retirando respuesta de comentario en respuesta aceptada ... Deje que las cosas corran por un corto tiempo:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];

También descubrí que necesito crear una ventana de UI y colocar la vista del controlador de vista en ella, como se indica en la respuesta más votada.


Debe asegurarse de que textField esté instalado en la jerarquía de vistas.

Si la propiedad de ventana de la vista contiene un objeto UIWindow, se ha instalado en una jerarquía de vistas; si devuelve cero, la vista se separa de cualquier jerarquía.

Esperemos que esto ayude ....


Supongo que la gestión / cambio de la primera cadena de respuesta se realiza de alguna manera en el bucle principal, cuando la interfaz de usuario se actualiza preparándose para el siguiente evento de manejo. Si esta hipótesis es correcta, simplemente haría lo siguiente:

-(void)assertIfNotFirstResponder:(UITextField*)field { STAssertTrue([field isFirstResponder], nil); } - (void)testFirstResponder { [controller view]; [[controller firstTextField] becomeFirstResponder]; [self performSelector:@selector(@"assertIfNotFirstResponder:") withObject:[controller firstTextField] afterDelay:0.0]; }

Nota: He usado un retraso de 0.0 porque simplemente quiero que el mensaje se coloque en la cola de eventos y se envíe lo antes posible. Necesito solo una forma de volver al bucle principal, para su mantenimiento. Esto no debería producir ningún retraso real en su caso. Si está ejecutando varias pruebas del mismo tipo, es decir, cambiando repetidamente el control que es el primer respondedor, esta técnica debe garantizar que todos los eventos se ordenen correctamente con los generados por el performSelector de performSelector .

Si está ejecutando sus pruebas desde un subproceso diferente, podría usar – performSelectorOnMainThread:withObject:waitUntilDone:


Usando Xcode 5.1 y XCTestCase , esto parece funcionar bien:

- (void)testFirstResponder { // Make sure the controller''s view has a window UIWindow *window = [[UIWindow alloc] init]; [window addSubview:controller.view]; // Call whatever method you''re testing [controller.textView becomeFirstResponder]; // Assert that the desired subview is the first responder XCTAssertTrue([sut.textView isFirstResponder]); }

Para que una vista / subvista se convierta en el primer respondedor, debe formar parte de una jerarquía de vistas , lo que significa que la propiedad de ventana de su vista raíz debe estar configurada.

Jon y Sergio mencionan que es posible que deba llamar a [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]] después de llamar a becomeFirstResponder en su subvista deseada, pero descubrí que esto no era necesario en nuestro caso.

Sin embargo, su millaje puede variar (incluso dependiendo de la versión de Xcode que esté usando), por lo que es posible que deba o no incluir dicha llamada.