objective c - Prueba OCUnit para protocolos/devoluciones de llamada/delegado en Objective-C
unit-testing delegates (2)
Usando OCUnit, ¿hay una manera de probar los protocolos de delegado?
Estoy intentando esto, que no funciona.
-(void) testSomeObjDelegate {
SomeObj obj = [[SomeObj alloc] initWithDelegate:self];
[obj executeMethod];
}
-(void) someObjDelegateMethod {
//test something here
}
Voy a intentar llamar al método obj
en un subproceso diferente y tendré el sueño de prueba hasta que se llame al delegado. Parece que debería haber una manera más fácil de probar esto.
Por favor, revise la Unidad de Acceso Asíncrono a la Red . Creo que puedo ayudarte. En resumen lo que hace es:
Agregue el siguiente método que se encargará de la sincronización entre el código de prueba de la unidad y el código asíncrono bajo prueba:
- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs {
NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
if([timeoutDate timeIntervalSinceNow] < 0.0)
break;
} while (!done);
return done;
}
Probar a un delegado es trivial. Simplemente establezca un ivar en la prueba en su método de devolución de llamada y verifíquelo después de lo que debería estar activando la devolución de llamada delegada.
Por ejemplo, si tengo una clase Something
que utiliza un delegado del protocolo SomethingDelegate
y envía ese delegate -something:delegateInvoked:
en respuesta a algún mensaje, puedo probarlo como ethis:
@interface TestSomeBehavior : SenTestCase <SomethingDelegate>
{
Something *_object;
BOOL _callbackInvoked;
}
@end
@implementation TestSomeBehavior
- (void)setUp {
[super setUp];
_object = [[Something alloc] init];
_object.delegate = self;
}
- (void)tearDown {
_object.delegate = nil;
[_object release];
[super tearDown];
}
- (void)testSomeBehaviorCallingBack {
[_object doSomethingThatShouldCallBack];
STAssertTrue(_callbackInvoked,
@"Delegate should send -something:delegateInvoked:");
}
- (void)something:(Something *)something delegateInvoked:(BOOL)invoked {
_callbackInvoked = YES;
}
@end
Sin embargo, creo que ya entiendes esto por la forma en que has formulado tu pregunta. (En general, publico esto para otros lectores). Creo que en realidad estás haciendo una pregunta más sutil: ¿Cómo puedo probar algo que puede ocurrir más tarde , como algo que hace girar el runloop? Mi señal es tu mención de dormir y ensartar.
En primer lugar, no debe invocar arbitrariamente un método en otro hilo. Solo debe hacerlo si está documentado para que sea seguro de usar de esa manera. La razón es que no sabes lo que hacen las partes internas de la clase. Por ejemplo, podría programar eventos en el bucle de ejecución, en cuyo caso la ejecución del método en un subproceso diferente hará que ocurran en un bucle de ejecución diferente. Esto entonces arruinaría el estado interno de la clase.
Si necesita probar algo que puede tardar un poco en pasar, puede hacerlo simplemente ejecutando el bucle de ejecución actual. Aquí es cómo podría volver a escribir el método de prueba individual anterior para hacer eso:
- (void)testSomeBehaviorCallingBack {
NSDate *fiveSecondsFromNow = [NSDate dateWithTimeIntervalSinceNow:5.0];
[_object doSomethingThatShouldCallBack];
[[NSRunLoop currentRunLoop] runUntilDate:fiveSecondsFromNow];
STAssertTrue(_callbackInvoked,
@"Delegate should send -something:delegateInvoked:");
}
Esto hará girar el bucle de ejecución actual en el modo predeterminado durante 5 segundos, bajo el supuesto de que -doSomethingThatShouldCallBack
programará su trabajo en el bucle de ejecución principal en el modo predeterminado. Por lo general, esto es correcto porque las API que funcionan de esta manera a menudo le permiten especificar un bucle de ejecución para usar, así como un modo para ejecutar. Si puede hacerlo, entonces puede usar -[NSRunLoop runMode:beforeDate:]
para ejecutar la ejecución en lugar de eso, haga un bucle en ese modo, haciendo que sea más probable que el trabajo que espera realizar sea.