Passing primitives to an OCMock's stub
I'm learning how to use OCMock to test my iPhone's project and I have this scenario: a HeightMap class with a getHeightAtX:andY:
method, and a Render class using HeightMap
. I'm trying to unit test Render using some HeightMap
mocks. This works:
id mock = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[mock stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:0 andY:0];
Of course, works only for x=0
and y=0
. I want to test using a "flat" height map. This means I need to do something like this:
id chunk = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[chunk stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:[OCMArg any] andY:[OCMArg any]];
But this raises two compilation warnings:
warning开发者_JAVA百科: passing argument 1 of
'getHeightAtX:andY:'
makes integer from pointer without a cast
and a runtime error:
unexpected method invoked:
'getHeightAtX:0 andY:0 stubbed: getHeightAtX:15545040 andY:15545024'
What am I missing? I found no way to pass a anyValue
to this mock.
It's been awhile since this question has been asked but I ran into this issue myself and couldn't find a solution anywhere. OCMock now supports ignoringNonObjectArgs
so an example of an expect
would be
[[[mockObject expect] ignoringNonObjectArgs] someMethodWithPrimitiveArgument:5];
the 5 doesn't actually do anything, just a filler value
OCMock doesn't currently support loose matching of primitive arguments. There's a discussion about potential changes to support this on the OCMock forums, though it seems to have stalled.
The only solution I've found is to structure my tests in such a way that I know the primitive values that will be passed in, though it's far from ideal.
Use OCMockito instead.
It supports primitive argument matching.
For instance, in your case:
id chunk = mock([Chunk class]);
[[given([chunk getHeightAtX:0]) withMatcher:anything() forArgument:0] willReturnInt:0];
In addition to Andrew Park answer you could make it a little bit more general and nice looking:
#define OCMStubIgnoringNonObjectArgs(invocation) \
({ \
_OCMSilenceWarnings( \
[OCMMacroState beginStubMacro]; \
[[[OCMMacroState globalState] recorder] ignoringNonObjectArgs]; \
invocation; \
[OCMMacroState endStubMacro]; \
); \
})
The you can use it like that:
OCMStubIgnoringNonObjectArgs(someMethodParam:0 param2:0).andDo(someBlock)
You can do the same for expecting. This case is for stubbing as topic starter request. It was tested with OCMock 3.1.1.
You could do like this:
id chunk = OCMClassMock([Chunk class])
OCMStub([chunk ignoringNonObjectArgs] getHeightAtX:0 andY:0]])
Readmore at: http://ocmock.org/reference/#argument-constraints
Despite being fairly hacky, the approach of using expectations to store the passed block to call later in the test code has worked for me:
- (void)testVerifyPrimitiveBlockArgument
{
// mock object that would call the block in production
id mockOtherObject = OCMClassMock([OtherObject class]);
// pass the block calling object to the test object
Object *objectUnderTest = [[Object new] initWithOtherObject:mockOtherObject];
// store the block when the method is called to use later
__block void (^completionBlock)(NSUInteger value) = nil;
OCMExpect([mockOtherObject doSomethingWithCompletion:[OCMArg checkWithBlock:^BOOL(id value) { completionBlock = value; return YES; }]]);
// call the method that's being tested
[objectUnderTest doThingThatCallsBlockOnOtherObject];
// once the expected method has been called from `doThingThatCallsBlockOnOtherObject`, continue
OCMVerifyAllWithDelay(mockOtherObject, 0.5);
// simulate callback from mockOtherObject with primitive value, can be done on the main or background queue
completionBlock(45);
}
精彩评论