3
votes

I have a method that I need to stub. The method is of the form below:

BOOL myMethodWithError:(*__autoreleasing *NSError)error;

So I mocked the object and attempted to return a nil back through 'error'. I coded it as follows.

id mockMyObject = [OCMockObject mockForClass:[MyObject class]];
BOOL retVal = YES;
NSError *error = nil;
[[[mockMyObject stub] andReturn:OCMOCK_VALUE(retVal)] myMethodWithError:&error];

When the test is run and the mock object is operated, the error reference id appears to change. So the mock throws an exception:

OCMockObject[MyObject]: expected method invoked: myMethodWithError:0xbfffca78

I have tried a number of different ways but each time the pointer value appears to change once the error object is passed to the method which causes the mock object to throw an error.

I simply need to test my business rules against the pass-by-reference value of the argument, but I can't seem to get the mock or test object to cooperate.

Thanks in advance, any help will be greatly appreciated.

2
I have a little more clarity to the problem. After doing some more digging into the OCMock source code tests I found where similar tests as mine were performed. The test used [OCMArg isAnyPointer] which returns a "void *". This was OK before ARC, but now ARC won't allow an implicit conversion between a 'void *' and a 'NSError *__autoreleasing *'. This now appears to be what I need to work around. - Rob
A much simpler way to work around this would be to make a hand-rolled mock. - Jon Reid

2 Answers

6
votes

Apart from the solutions Ben mentions in his answer(I only tested the one based on ignoringNonObjectArgs, and it works fine), I prefer to use [OCMArg anyPointer] with the appropriate cast:

[[[myMock stub] andReturn:something] someMethod:(NSError * __autoreleasing *)[OCMArg anyPointer]];
2
votes

Use ignoringNonObjectArgs

[[[[mock stub] andReturnValue:OCMOCK_VALUE((BOOL){YES})] ignoringNonObjectArgs] myMethodWithError:NULL];

From http://ocmock.org/features/

Arguments that are neither objects nor pointers or selectors cannot be ignored using an any placeholder. It is possible, though, to tell the mock to ignore all non-object arguments in an invocation:

[[[mock expect] ignoringNonObjectArgs] someMethodWithIntArgument:0] 

In this case the mock will accept any invocation of someMethodWithIntArgument: no matter what argument is actually passed. If the method has object arguments as well as non-object arguments, the object arguments can still be constrained as usual using the methods on OCMArg.

Bonus Answer

This would also solve your issue:

[[[mock stub] andReturnValue:OCMOCK_VALUE((BOOL){YES})] myMethodWithError:[OCMArg setTo:nil]];