iosocmock

[OCMock][OCMProtocolMock][OCMStub]When I OCMProtocolMock a protocol(This protocol has a method),How can I invoke the real implementation of the method


code show as below:

- (void)test_method {
    id mockDelegate = OCMProtocolMock(@protocol(adDelegate));
    OCMExpect([mockDelegate adLoaded:OCMOCK_ANY error:OCMOCK_ANY]);
    self.delegate = mockDelegate;
    if ([self.delegate respondsToSelector:@selector(adLoaded:error:)]) {
         [self.delegate adLoaded:array error:nil];
    }
    OCMVerifyAllWithDelay(mockDelegate, 15);
}

// adDelegate callback method
- (void)adLoaded:array:(NSArray*)array error:(NSError *)error {
    ......
    ......
}

Because I let:self.delegate = mockDelegate,So this method cannot be invoked.

How can I invoke the real implementation of the method?

Update February 10th:

I use:

 OCMStub([mockDelegate adLoaded:OCMOCK_ANY error:OCMOCK_ANY])
      .andDo(^BOOL(id<adDelegate> localSelf, NSArray *array, NSError *error) {
        *error = [NSError errorWithDomain:@"Error" code:0 userInfo:nil];
        return NO;
      });

There is an error:

Incompatible block pointer types passing 'BOOL (^)(__strong id<adDelegate>, NSArray *__strong, NSError *__strong)' to parameter of type 'void (^__strong)(NSInvocation *__strong)'

Please advise how to solve?

Update in a few hours

I found the answer, so this can be achieved:

[OCMExpect([adDelegate adLoaded:OCMOCK_ANY error:OCMOCK_ANY]) andDo:^(NSInvocation *invocation) {
        __unsafe_unretained NSArray *objects = nil;
        [invocation getArgument:&objects atIndex:2];
        
        __unsafe_unretained NSError *error = nil;
        [invocation getArgument:&error atIndex:3];
        
        [self adLoaded:objects error:error];
    }];

In this way, the implementation can obtain the parameters passed in when the delegate callback is triggered,and then pass the parameters in the unit test class and manually call the delegate callback.


Solution

  • I would use an OCMExpect().andDo(). Note that using andDo with OCMock in its current state is a little tricky with regards to getting the memory management right. See https://github.com/erikdoe/ocmock/pull/470 for details.

    Probably something like:

    OCMExpect([mockDelegate adLoaded:OCMOCK_ANY error:OCMOCK_ANY])
    .andDo(^(NSInvocation *invocation) {
            __unsafe_unretained NSArray *array = nil;
            __unsafe_unretained NSError *error = nil;
            [invocation getArgument:&array atIndex:2];
            [invocation getArgument:&error atIndex:3];
            [self adLoaded:array error:error];
          });
    

    or if you patch in pull 470:

    OCMExpect([mockDelegate adLoaded:OCMOCK_ANY error:OCMOCK_ANY])
    .andDo(^void(id<adDelegate> localSelf, NSArray *array, NSError *error) {
      [self adLoaded:array error:error];
    });