EXC_BAD_ACCESS在访问OCMock的andDo参数时
我正在尝试使用OCMock的stub和Do方法编写一段代码。
在这种情况下,正在testingUIImageView扩展类。 我想检查扩展调用[self setImage:]参数是非零(稍后将使用其他图像比较)。
在使用OCMock的andDo方法时,在块完成后,testing会使用EXC_BAD_ACCESS进行崩溃。
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];
我现在发现的唯一解决scheme是使用andCall而不是andDo ,但这使testing变得复杂。
我可以用andDo避免崩溃吗?
更新那么,我将尝试在这里给出一个更好的例子:这是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"); }
这里是testing代码(来自PInfo的单一方法):
- (void)startDownloadingImagesAsync:(bool)isThumbnailImg { NSInvocationOperation *inv; inv = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadThumbnailWorker:) object:nil]; [[self downloadQueue] addOperation:inv]; }
使用EXC_BAD_ACCESS从startDownloadingImagesAsync退出时,代码仍然崩溃。 如果在andDo块中添加一个断点,我会看到控件到达了这个点,并通过getArgument获取了正确的对象。
然而,如果我在块中使用getArgument ,它会崩溃无论我尝试做什么。
PS感谢您的帮助。
在使用NSProxy的forwardInvocation:方法时遇到了类似的问题。
你可以试试下面吗?
NSInvocationOperation *op; // Change this line __unsafe_unretained NSInvocationOperation *op; // to this line
或者另一种方法可能是保留NSInvocation的论点:
[invocation retainArguments];
稍后我会尝试添加更详细的解释。
我认为问题是你正试图直接调用一个模拟对象。 对于你想要做的,你不应该需要一个模拟对象。 只需调用该方法并validation图像是否已设置:
expect(myObject.imageView.image).to.beNil(); [myObject do_something_that_calls_setImage]; expect(myObject.imageView.image).not.to.beNil();
如果你真的想使用模拟出于某种原因,你可以做一个真正的UIImageView
和部分模拟:
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();
在我的情况下,这是因为我给这个方法引入了另一个参数,所以块参数被移动了一个。
我通过将[inv getArgument:&op atIndex:2]
更改为[inv getArgument:&op atIndex:3]