Reputation: 6385
Sometimes I get a EXC_BAD_ACCESS when running this test:
- (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 happens here:
- (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
}
}
The weird thing is that it never crashes when I run only this one test, but I crashes almost always when I tun all my tests (with cmd+u).
I tried to add [invocation retainArguments]
, it did not help, and I think should not be here.
Anyone had such problems?
Upvotes: 4
Views: 1370
Reputation: 9480
I'm experiencing the same problem with OCMock 3.
I notice the crash was in the method stopMocking
. According to OCMock docs "The mock automatically calls stopMocking
during its own deallocation." (http://ocmock.org/reference/)
In my code, some methods execute other tasks in the background (using GCD), which may continue executing even after the test finishes. Therefore it was trying to access a mock that had already been deallocated and hence the crash.
In order for the tasks to be completed, I added a timer in the tearDown
method like this:
[NSThread sleepForTimeInterval:0.05];
This will give time for the tasks to execute before the mock is deallocated.
Hope this is helpful!
Upvotes: 1
Reputation: 1079
Given it is only failing when the tests are run together, it may be that one of the mock objects for a class you are testing remains after a particular test. For example, lets say your cacheMock
is stubbing a method in a test (lets call it testOne
).
After testOne
is run, if you don't explicitly call [self.cacheMock stopMocking]
at the end of it, the stub will still be on for the next test case, which may cause failures when trying to capture the arguments through the invocation.
In other words, verify that all your mocks are stopped in each test case, or at least the ones you may mock again. I would guess that either cacheMock
or imageLoaderMock
are causing the issue.
Upvotes: 2