我正在尝试使用OCMock的stub 和Do 方法编写一段代码。
在这种情况下,正在测试UIImageView扩展类。我想检查扩展名是否使用非零参数调用 [self setImage:] (稍后将使用其他图像比较)。
使用OCMock的和Do 方法时,在块完成后,测试会与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];
我现在找到的唯一解决方案是使用 andCall 而不是 andDo ,但这会使测试变得复杂。
我可以使用 andDo 来避免崩溃吗?
更新 好吧,我会尝试在这里给出一个更好的例子: 这是测试代码的新部分:
- (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");
}
以下是经过测试的代码(来自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 ,它会崩溃我试图做的事情。
P.S。谢谢你的帮助。
答案 0 :(得分:29)
使用NSProxy的forwardInvocation:方法时遇到了类似的问题。
你可以试试下面的吗?
NSInvocationOperation *op; // Change this line
__unsafe_unretained NSInvocationOperation *op; // to this line
或者另一种方法可能是保留NSInvocation的参数:
[invocation retainArguments];
我稍后会尝试添加更详细的解释。
答案 1 :(得分:0)
我认为问题在于您正在尝试直接调用模拟对象。对于你想要做的事情,你不应该需要一个模拟对象。只需调用该方法并验证图像已设置:
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();
答案 2 :(得分:0)
在我的情况下,这种情况正在发生,因为我向此方法引入了另一个参数,因此块参数被移动了一个。
我通过将[inv getArgument:&op atIndex:2]
更改为[inv getArgument:&op atIndex:3]