gamda gamda - 1 year ago 127
iOS Question

OCMock throwing EXC_BAD_ACCESS

I have just downloaded OCMock to use for testing a library I am working on. I ran into issues in the very first stub I tried to do. I have an object that handles all network operations, and I have another object that has a map where it paints information received. I want to mock the network object to test the map object.

Here is my test file:

@interface STMap ()

@property (retain) STNetwork* router;


@interface testSTMap : XCTestCase <STMapDelegate>

@property (retain) MKMapView* mapView;
@property (retain) STMap* testMap;
@property (retain) id mockRouter;


@implementation testSTMap

- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.mapView = [[MKMapView alloc] init];
self.testMap = [[STMap alloc] initWithDelegate:self andKey:@"test" andRouteOptions:nil
andMap:self.mapView andOverlayLevel:MKOverlayLevelAboveLabels];
self.mockRouter = OCMClassMock([STNetwork class]);
self.testMap.router = self.mockRouter;

- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
OCMStub([self.mockRouter getRouteForStartLat:[OCMArg any] andStartLon:[OCMArg any]
andEndLat:[OCMArg any] andEndLon:[OCMArg any]])._andReturn(nil);
[self.testMap addRouteForStartLat:@0 andStartLon:@0 andEndLat:@1 andEndLon:@1];

As you can see, I retain all 3 properties so the error doesn't come from the test itself. My map object has private properties, including the network object, this is why I created an extension in the test to be able to change it to the mock object. At this point, I am not even calling the map object yet, so I will not post its code.

The network object looks like this (all properties are private):

@interface STNetwork ()

@property (retain) NSString* url;
@property (weak) id<STNetworkDelegate> delegate;
@property (retain) NSString* key;
@property (copy) CompletionBlock completionHandler;


I know the delegate property must be weak to avoid retain cycles, so I doubt this is causing the error.

The error is thrown in the line with
. Trace:

  • OCMStubRecorder.m
    - line 112: if(OCMIsObjectType([aValue objCType])). At this point,
    is nil, this is where the problem starts, but I don't know where
    came from.

  • OCMFunctions.m
    line 78: const char *unqualifiedObjCType = OCMTypeWithoutQualifiers(objCType);. Here,
    is NULL, as expected since
    is nil.

  • OCMFunctions.m
    line 40: while(strchr("rnNoORV", objCType[0]) != NULL). Here is where the bad access actually happens.

Things I tried:

  • Changing the [OCMArg any] to hard coded values

  • Returning a number, NSNull, and void from the mock

None of these got me past the bad access. Any help is greatly appreciated!

- (void)getRouteForStartLat: (NSNumber*) startLat
andStartLon: (NSNumber*) startLon
andEndLat: (NSNumber*) endLat
andEndLon: (NSNumber*) endLon;

Answer Source

Have you tried using andReturn()? The version with the underscore prefix is for internal use only.