2

In the code I'm testing, I have an NSPredicate and I'm filtering an array:

NSPredicate* predicate = [NSPredicate predicateWithFormat:@"status == %d || status == %d", FVFileReadyStatus, FVFileWaitingStatus];
[myArray filterUsingPredicate:predicate];

I have a method to return a mock, which will eventually get added to myArray. FVFileStatus is a typedef enum. Because I'm using a predicate, the predicate is calling valueForKey, so I need to stub that out:

-(id)mockFVFileHandleWithStatus:(FVFileStatus)status {
    id mock = [OCMockObject mockForClass:[FVFileHandle class]];
    [[[mock stub] andReturnValue:OCMOCK_VALUE(status)] valueForKey:[OCMArg checkWithSelector:@selector(isEqualToString:) onObject:@"status"]];
    return mock;
}

When I run my test, it fails on the filter. I get an NSInvalidArgumentException - Reason: Return value does not match method signature.

I'm not sure how to setup the stub so it will work with an NSPredicate.

Can anybody help?

Tim Reddy
  • 4,340
  • 1
  • 40
  • 77

1 Answers1

4

Very close. The right way to set up the stub is as follows:

[[[mock stub] andReturn:OCMOCK_VALUE(status)] valueForKey:[OCMArg checkWithSelector:@selector(isEqualToString:) onObject:@"status"]];

This might seem counter-intuitive at first, because the attribute you are trying to stub is of type int, and because of that you'd expect to have to use andReturnValue:.

However, the actual method that is being called on the mock object is not status but valueForKey: and the return type for the latter is id. So, when using andReturnValue: the stub is set up to return a primitive value and then complains when it's asked to provide an object. By the way, the error message could be clearer, I'll look into that.

You can still use the OCMOCK_VALUE macro to set up a value object, but by using andReturn: you're telling the stub to return that value object, and not the primitive that's wrapped in it, and that is what is compatible with valueForKey:'s return type.

Erik Doernenburg
  • 2,933
  • 18
  • 21
  • I'm pretty sure you don't need to use -[OCMArg checkWithSelector:] and can just use the string as the -valueForKey: argument. – Greg Feb 13 '13 at 21:10