与OCMock随机崩溃

时间:2015-07-06 14:19:09

标签: objective-c unit-testing memory-management ocmock

有时我在运行此测试时会得到一个EXC_BAD_ACCESS:

- (void)testThatItDoesNotSaveLoadedImageIfNotIntializedWithModifiesFileCacheOption {

    id cacheMock = OCMClassMock([BEImageCache class]);
    id imageLoaderMock = OCMClassMock([BEImageLoader class]);

    BETwoLayerCacheImageProvider *imageProvider = [[BETwoLayerCacheImageProvider alloc] initWithCache:cacheMock imageLoader:imageLoaderMock options:0 scale:2.f];
    UIImage *expectedImage = [UIImage new];
    [[cacheMock reject] saveImageAtURLInFileCache:[OCMArg any] forURL:[OCMArg any]];
    [[cacheMock reject] saveImageInFileCache:[OCMArg any] forURL:[OCMArg any]];

    __block NSURL *URL = [NSURL fileURLWithPath:@"/file:///fixtureURL"];
    __block typeof(self) welf = self;
    OCMStub([imageLoaderMock downloadImageWithURL:[OCMArg any] completionCallback:[OCMArg any]]).andDo(^(NSInvocation *invocation) {

        ///[invocation retainArguments];
        void (^callback)(UIImage *image, NSError *error, NSString *imageURL, NSURL *temporaryImageURL) = nil;
        [invocation getArgument:&callback atIndex:3];
        callback(expectedImage, nil, welf.smallImageURL, URL);
    });

    [imageProvider fetchImageForImageData:self.imageData size:self.smallImageSize withCompletionCallback:^(UIImage *anImage, id<BEImageAware> imageData, CGSize requestedSize) {

        OCMVerifyAll(cacheMock);
    }];
}

EXC_BAD_ACCESS在这里发生:

- (void)forwardInvocationForClassObject:(NSInvocation *)anInvocation
{
    // in here "self" is a reference to the real class, not the mock
    OCClassMockObject *mock = OCMGetAssociatedMockForClass((Class) self, YES);
    if(mock == nil)
    {
        [NSException raise:NSInternalInconsistencyException format:@"No mock for class %@", NSStringFromClass((Class)self)];
    }
    if([mock handleInvocation:anInvocation] == NO)
    {
        [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])];
        [anInvocation invoke]; /// EXC_BAD_ACCESS
    }
}

奇怪的是,当我只运行这一个测试时它永远不会崩溃,但是当我调试所有测试时(使用cmd + u),我几乎总是崩溃。

我试图添加[invocation retainArguments],它没有帮助,我认为不应该在这里。 有人有这样的问题吗?

2 个答案:

答案 0 :(得分:2)

鉴于它只是在测试一起运行时失败,可能是您正在测试的类的一个模拟对象在特定测试之后仍然存在。例如,假设您的cacheMock在测试中存根方法(让我们称之为testOne)。

运行testOne后,如果您未在其末尾显式调用[self.cacheMock stopMocking],则存根仍会在下一个测试用例中打开,这可能会在尝试时导致失败通过调用捕获参数。

换句话说,验证每个测试用例中的所有模拟停止,或者至少再次模拟。我猜是cacheMockimageLoaderMock引起了问题。

答案 1 :(得分:1)

我遇到了与OCMock 3相同的问题。

我注意到崩溃发生在方法stopMocking中。根据OCMock文档“模拟在自己的释放期间自动调用stopMocking。” (http://ocmock.org/reference/

在我的代码中,一些方法在后台执行其他任务(使用GCD),即使在测试完成后也可以继续执行。因此,试图访问已经解除分配的模拟并因此崩溃。 为了完成任务,我在tearDown方法中添加了一个计时器,如下所示:

[NSThread sleepForTimeInterval:0.05];

这将为在取消分配模拟之前执行任务提供时间。

希望这有用!