4

I'm writing unit tests to my Facebook SDK wrapper and something got me confused about NSInvocation's - (void)getArgument:(void *)buffer atIndex:(NSInteger)index while trying to mock FBRequest with OCMock.

Here's the method definition I'm trying to test.

-(void) friendListInstalledOnly:(BOOL) installedOnly withCompletionHandler:(FacebookHelperCompletionHandler)handler

where FacebookHelperCompletionHandler is a typedef as follows:

typedef void (^FacebookHelperCompletionHandler)(id result, NSError  *error);

Here is my test method

-(void) testFriendsListInstalledOnly {

id mockRequest = [OCMockObject mockForClass:[FBRequest class]];

NSArray *friendsArray = [NSArray arrayWithObjects:
                         @{@"id":@(1),@"name":@"Kaan"},
                         @{@"id":@(2),@"name":@"Mumtaz",@"installed":@(1)},
                         @{@"id":@(3),@"name":@"Toprak",@"installed":@(0)},
                         @{@"id":@(4),@"name":@"Yeter"},nil];

NSDictionary<FBGraphObject> *responseDictionary = [FBGraphObject graphObjectWrappingDictionary:@{@"data":friendsArray}];

[[mockRequest expect] setGraphPath:[OCMArg any]];

[[[mockRequest expect] andDo:^(NSInvocation *invocation) {

    FBRequestHandler requestHandler = nil;
    [invocation getArgument:&requestHandler atIndex:3];
    requestHandler(nil,responseDictionary,nil);

}] startWithCompletionHandler:[OCMArg any]];


self.facebookHelper.friendsRequest = mockRequest;

[self.facebookHelper friendListInstalledOnly:YES withCompletionHandler:^(id result, NSError *error) {
    NSLog(@"%@",result); // The actual assert will go here.
}];
}

When I pass 3 as index in the NSInvocation method, I get an error saying that index 3 is out of bounds. But the documentation says that index 0 is self, 1 is _cmd, so I believe that installedOnly should be 2 and completionHandler should be 3. I played with it and passing 2 for index gets me my desired completion handler and test works. I just want to understand why these indexes are working wrong (maybe something with primitive types?)

EDIT: Of course, stupid me... I was mocking FBRequest's - (FBRequestConnection*)startWithCompletionHandler:(FBRequestHandler)handler method where the handler is at index 2. I'm leaving the question just in case someone needs block stubbing with OCMock in the future. `

Kaan Dedeoglu
  • 14,765
  • 5
  • 40
  • 41
  • 1
    Just to say that you can also use [OCMArg checkWithBlock:](check this question http://stackoverflow.com/questions/16530194/can-ocmock-run-a-block-parameter). Personally I find it more clear since you don't need to deal with the NSInvocation. – e1985 Jul 29 '13 at 11:09
  • @e1985 very cool, thank you for the tip! – Kaan Dedeoglu Jul 29 '13 at 12:12
  • 2
    Another note, if using ARC, use __unsafe_unretained on the local variables used to pull back any object arguments from NSInvocations. Otherwise the pointer gets magically set by NSInvocation (which bypasses ARC) since it's typed as "void *", but ARC will add an extra release when the variable goes out of scope. – Carl Lindberg Aug 02 '13 at 16:20

0 Answers0