2

I have 2 methods in a class where one of them simply calls the other one with specific parameters. The methods are as below:

-(void)loadAllFollowersForUser:(NSUInteger)userID withResponseHandler:(_Nullable CompletionHandler)handler {
[self loadFollowersForUser:userID
                fromOffSet:0
                   toLimit:100000
       withResponseHandler:handler];
}

-(void)loadFollowersForUser:(NSUInteger)userID fromOffSet:(NSInteger)offset toLimit:(NSInteger)limit withResponseHandler:(_Nullable CompletionHandler)handler {
    NSLog(@"Actual loadFollowersForUser method got called!");
}

I am trying my hand on TDD and have been using OCMock. I have the following test that simply tests that loadAllFollowers is internally calling the other method

- (void)testLoadAllFollowersCallsLoadFollowers {
    id partialMockSUT = OCMPartialMock(self.sut);

    OCMExpect([partialMockSUT loadFollowersForUser:[OCMArg any]
                                         fromOffSet:[OCMArg any]
                                            toLimit:[OCMArg any]
                                withResponseHandler:[OCMArg any]]);

    [partialMockSUT loadAllFollowersForUser:123
                           withResponseHandler:^(BOOL success, id response, NSError *error) {

                           }];

    OCMVerifyAll(partialMockParser);

}

I am using a partial mock because I only want to stub the loadFollowersForUser method and call the actual implementation of loadAllFollowers method. This does almost exactly this but my test always fails to meet the expectation and I see the NSLog in the console.

Things I have tried:

  1. I have tried adding other temporary methods to verify the behavior of parital mocks and they perform exactly as expected
  2. This question suggests what I am trying to do should be very much possible
  3. I have tried adding OCMStub for the method after the OCMExpect inline with OCMock documentation. See 10.2 on this page

I am not sure if its a problem with block being passed in or that the method return type is void and I have no action for the expectation.

Community
  • 1
  • 1
Numan Tariq
  • 1,296
  • 1
  • 9
  • 18
  • 1
    A quick look at the OCMock docs at http://ocmock.org/reference/#argument-constraints reveals "Arguments that are neither objects nor pointers or selectors cannot be ignored using an any placeholder" and a workaround. That might be the issue, since you have scalar arguments there. – marramgrass May 26 '16 at 16:12
  • Thanks! That seems to be working. It is weird that the exception it throws is about expectation not being met rather than throwing a warning/error about any constraint vs scalar values. This had me stumped for a good few hours. Can you please post this as an Answer and I will accept it after some more testing? – Numan Tariq May 26 '16 at 16:30

1 Answers1

3

According to the OCMock docs, the [OCMArg any] placeholder only passes "objects, pointers and selectors".

The problem here may be that there are scalar arguments to the method, so the expectation is failing. The docs suggest a workaround to handle the scalar arguments by stubbing the method via a call to ignoringNonObjectArgs. So that might look like:

OCMExpect([[partialMockSUT ignoringNonObjectArgs]
                       loadFollowersForUser:[OCMArg any]
                                 fromOffSet:0  // or any value
                                    toLimit:0  // or any value
                        withResponseHandler:[OCMArg any]]);

Not 100% sure since I haven't tried it myself.

marramgrass
  • 1,411
  • 11
  • 17
  • The user ID in my case is NSUInteger which means the first argument should also be scalar. Thanks for your help! Onto testing block based completion handlers now :) – Numan Tariq May 27 '16 at 09:33