erikdoe / ocmock

Mock objects for Objective-C
http://ocmock.org
Apache License 2.0
2.16k stars 606 forks source link

Bad access on iOS 10 simulator #317

Closed marcuswu0814 closed 4 years ago

marcuswu0814 commented 8 years ago

I running my unit test with OCMock, it always crash in specific test method when I run all the test method (about 20), but if I run the test method alone, it passed.

bad access crash in OCPartialMockObject's method forwardInvocationForRealObject:'s [anInvocation invoke];:

- (void)forwardInvocationForRealObject:(NSInvocation *)anInvocation
{
    // in here "self" is a reference to the real object, not the mock
    OCPartialMockObject *mock = OCMGetAssociatedMockForObject(self);
    if(mock == nil)
        [NSException raise:NSInternalInconsistencyException format:@"No partial mock for object %p", self];

    if([mock handleInvocation:anInvocation] == NO)
    {
        [anInvocation setSelector:OCMAliasForOriginalSelector([anInvocation selector])];
        [anInvocation invoke];
    }
}

I guess my mock viewController be dealloc, but why? If need much more crash information, please let me know, thanks!

BTW, the test suite passed all the time when I running test on iOS 9 simulator.

umut-genlik commented 7 years ago

I get the same error too, exc_bad_access, everything works perfect when test target is ios 8 or 9, but ios 10 simulator in xcode 8 throws an error.

when I put breakpoints I see that this line causes it

 id mockSharedInstance = OCMPartialMock([AVAudioSession sharedInstance]);
screen shot 2016-11-07 at 3 51 50 pm

Looks like an infinite loop to me.

whole function is

- (void)testPresentFromRootPermissionReportResult {

    id deviceUtilMock = OCMClassMock([XMDeviceUtil class]);
    OCMStub([deviceUtilMock isSimulator]).andReturn(NO);

    id strategyMock = OCMClassMock([XAPermissionStrategy class]);
    id viewControllerMock = OCMClassMock([UIViewController class]);

    XAStrategyResult *result = [XAStrategyResult resultForStrategy:strategyMock];
    result = [result requestRecordPermissionResult:YES];

    NSError *error = [[NSError alloc] init];

    //Setup the mock for AVAudioSession, //They have to not have permission
    id mockSharedInstance = OCMPartialMock([AVAudioSession sharedInstance]);
    OCMStub([mockSharedInstance recordPermission]).andReturn(AVAudioSessionRecordPermissionUndetermined);

    XAPermissionStrategyService *service = [XAPermissionStrategyService serviceWithDevServer:YES];
    id servicePartialMock = OCMPartialMock(service);
    OCMExpect([servicePartialMock reportPermissionStrategyResult:result success:[OCMArg any] failure:[OCMArg any]]);

    id settingsMock = OCMClassMock([XASettings class]);

    id permissionServiceMock = OCMClassMock([XAPermissionStrategyService class]);
    OCMStub([permissionServiceMock service]).andReturn(servicePartialMock);

    //Expect this to be called and pass the args through
    OCMExpect([strategyMock fromViewController:viewControllerMock requestRecordPermission:([OCMArg invokeBlockWithArgs:result, error, nil])]);

     //the test
    XARecordPermissionCompanionViewController *companion = [[XARecordPermissionCompanionViewController alloc] initWithStrategy:strategyMock settings:settingsMock];
    [companion presentFromViewController:viewControllerMock];

    OCMVerifyAllWithDelay(strategyMock, 1);
    OCMVerifyAllWithDelay(servicePartialMock, 1);
}
umut-genlik commented 7 years ago

This solved it but I am not sure if it is the correct way to do it?

https://blog.uship.com/shippingcode/unit-testing-around-singletons-with-ocmock/

id mockSharedInstance = [OCMockObject niceMockForClass:[AVAudioSession class]];
    [[[mockSharedInstance stub] andReturn:mockSharedInstance] sharedInstance];
    OCMStub([mockSharedInstance recordPermission]).andReturn(AVAudioSessionRecordPermissionDenied);

....test then

 [mockSharedInstance stopMocking];
amitfluke commented 7 years ago

I see random crashes while using OCMock for iOS 10 simulator. Is there any plan to release a new version for iOS 10

erikdoe commented 4 years ago

Closing due to inactivity.