【问题标题】:Random crash with OCMockOCMock 随机崩溃
【发布时间】:2015-07-06 14:19:09
【问题描述】:

运行此测试时,有时我会收到 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],但没有帮助,我认为不应该在这里。 有人遇到过这样的问题吗?

【问题讨论】:

  • 失败的堆栈跟踪中有什么有趣的地方吗?如果您运行除此之外的所有测试,它们是否始终通过?

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


【解决方案1】:

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

testOne 运行后,如果你没有在其末尾显式调用[self.cacheMock stopMocking],stub 仍然会为下一个测试用例打开,这可能会导致尝试通过调用。

换句话说,验证您的所有模拟是否在每个测试用例中都已停止,或者至少是您可以再次模拟的那些。我猜是cacheMockimageLoaderMock 导致了这个问题。

【讨论】:

  • 我认为我应该只将stopMocking 用于部分模拟和存根类方法。 stopMocking 对局部模拟变量也是必要的,有什么原因吗? (我更新了我的问题以明确cacheMockimageLoaderMock 都不是部分模拟)。我尝试添加stopMocking 电话,不幸的是它没有帮助
【解决方案2】:

我在使用 OCMock 3 时遇到了同样的问题。

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

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

[NSThread sleepForTimeInterval:0.05];

这将给任务在释放模拟之前执行的时间。

希望这有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-17
    • 2013-08-23
    • 2013-04-21
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多