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;
@end
@interface testSTMap : XCTestCase <STMapDelegate>
@property (retain) MKMapView* mapView;
@property (retain) STMap* testMap;
@property (retain) id mockRouter;
@end
@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;
@end
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 OCMStub. Trace:
OCMStubRecorder.m- line 112: if(OCMIsObjectType([aValue objCType])). At this point,aValueis nil, this is where the problem starts, but I don't know whereaValuecame from.OCMFunctions.mline 78: const char *unqualifiedObjCType = OCMTypeWithoutQualifiers(objCType);. Here,objCTypeis NULL, as expected sinceaValueis nil.OCMFunctions.mline 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;
getRouteForStartLat:andStartLon:andEndLat:andEndLon:method? - Erik Doernenburg