EXC_BAD_ACCESS al acceder a los parameters en y Hacer de OCMock

Estoy intentando escribir un bloque de código utilizando el método stub y Do de OCMock .

En este caso, la class de extensión UIImageView se está probando. Quiero comprobar que la extensión llama [self setImage:] con un parámetro que no es nulo (luego se utilizará otra comparación de imágenes).

Al utilizar el método OCMock's andDo , la testing se bloquea con EXC_BAD_ACCESS una vez que el bloque finaliza.

id mockView = [OCMockObject mockForClass:[UIImageView class]]; [[[mockView stub] andDo:^(NSInvocation *invocation) { UIImage *img; [invocation getArgument:&img atIndex:2]; <---- line causing the exception somebodySetImage |= (img != nil); }] setImage:OCMOCK_ANY]; [mockView do_something_that_calls_setImage]; 

La única solución que he encontrado por ahora es usar and Call en lugar de andDo , pero esto complica la testing.

¿Puedo evitar el locking con andDo ?

ACTUALIZACIÓN Bueno, trataré de dar un mejor ejemplo aquí: aquí está la nueva pieza del código de testing:

 - (void)testDownloadingThumbnail { PInfo *_sut = [[PInfo alloc] init]; __block id target = nil; id mock = [OCMockObject mockForClass:[NSOperationQueue class]]; [[[mock expect] andDo:^(NSInvocation *inv) { NSInvocationOperation *op; [inv getArgument:&op atIndex:2]; target = [[op invocation] target]; /* replacing this line with STAssert does not help either */ }] addOperation:OCMOCK_ANY]; [_sut setDownloadQueue:mock]; [_sut startDownloadingImagesAsync:YES]; [mock verify]; STAssertEqualObjects(target, _sut, @"invalid op target"); } 

Aquí está el código probado (método único de PInfo):

 - (void)startDownloadingImagesAsync:(bool)isThumbnailImg { NSInvocationOperation *inv; inv = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadThumbnailWorker:) object:nil]; [[self downloadQueue] addOperation:inv]; } 

El código aún falla al salir de startDownloadingImagesAsync con EXC_BAD_ACCESS. Si agrego un punto de interrupción dentro del bloque andDo , veo que el control llega a este punto y recupera objects correctos a través de getArgument .

Sin embargo, si uso getArgument dentro del bloque, se bloquea todo lo que bash hacer.

PS Gracias por la ayuda.

Me encontré con un problema similar al utilizar el método forwardInvocation: método de NSProxy.

¿Puedes probar lo siguiente?

 NSInvocationOperation *op; // Change this line __unsafe_unretained NSInvocationOperation *op; // to this line 

O bien, otro enfoque podría ser retener los arguments de NSInvocation:

 [invocation retainArguments]; 

http://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html#//apple_ref/occ/instm/NSInvocation/retainArguments

Intentaré agregar una explicación más detallada más adelante.

Creo que el problema es que estás intentando invocar un object simulado directamente. Por lo que intentas hacer, no deberías necesitar un object simulado. Simplemente llame al método y verifique que la image se haya configurado:

 expect(myObject.imageView.image).to.beNil(); [myObject do_something_that_calls_setImage]; expect(myObject.imageView.image).not.to.beNil(); 

Si realmente quieres usar un simulacro por alguna razón, puedes hacerlo con un UIImageView real y una simulación parcial:

 UIImageView *imageView = myObject.imageView; id mockView = [OCMockObject partialMockForObject:imageView]; __block BOOL imageSet = NO; [[[mockView stub] andDo:^(NSInvocation *invocation) { UIImage *img; [invocation getArgument:&img atIndex:2]; imageSet = (img != nil); }] setImage:OCMOCK_ANY]; [myObject do_something_that_calls_setImage]; expect(imageSet).to.beTruthy(); 

En mi caso, esto estaba sucediendo porque introduje otro parámetro en este método, por lo que el parámetro de bloque fue cambiado por uno.

Lo arreglé cambiando [inv getArgument:&op atIndex:2] a [inv getArgument:&op atIndex:3]