将原语传递给OCMock的存根

时间:2011-06-12 23:02:12

标签: xcode primitive ocmock

我正在学习如何使用OCMock来测试我的iPhone项目,我有这样的场景:一个带有getHeightAtX:andY:方法的HeightMap类和一个使用HeightMap的Render类。我正在尝试使用一些HeightMap模拟单元测试渲染。这有效:

id mock = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[mock stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:0 andY:0];

当然,仅适用于x=0y=0。我想测试使用“平面”高度图。这意味着我需要做这样的事情:

id chunk = [OCMockObject mockForClass:[Chunk class]];
int h = 0;
[[[chunk stub] andReturnValue:OCMOCK_VALUE(h)] getHeightAtX:[OCMArg any] andY:[OCMArg any]];

但是这引发了两个编译警告:

  

警告:传递'getHeightAtX:andY:'的参数1使指针中的整数不带强制转换

和运行时错误:

  

调用了意外的方法:'getHeightAtX:0 andY:0 stubbed: getHeightAtX:15545040 andY:15545024'

我错过了什么?我发现无法将anyValue传递给此模拟器。

6 个答案:

答案 0 :(得分:49)

自问这个问题已经有一段时间了,但我自己遇到了这个问题,无法在任何地方找到解决方案。 OCMock现在支持ignoringNonObjectArgs,因此expect的示例将是

[[[mockObject expect] ignoringNonObjectArgs] someMethodWithPrimitiveArgument:5];

5实际上没有做任何事情,只是填充值

答案 1 :(得分:18)

OCMock目前不支持原始参数的松散匹配。有关支持这个on the OCMock forums的潜在变化的讨论虽然似乎已停滞不前。

我发现的唯一解决方案是以这样的方式构建我的测试,即我知道将传入的原始值,尽管它远非理想。

答案 2 :(得分:2)

改为使用OCMockito

它支持原始参数匹配。

例如,在您的情况下:

id chunk = mock([Chunk class]);
[[given([chunk getHeightAtX:0]) withMatcher:anything() forArgument:0] willReturnInt:0];

答案 3 :(得分:1)

除了安德鲁·帕克之外,你可以让它变得更加通用和漂亮:

#define OCMStubIgnoringNonObjectArgs(invocation) \
({ \
    _OCMSilenceWarnings( \
        [OCMMacroState beginStubMacro]; \
        [[[OCMMacroState globalState] recorder] ignoringNonObjectArgs]; \
        invocation; \
        [OCMMacroState endStubMacro]; \
    ); \
})

你可以这样使用它:

OCMStubIgnoringNonObjectArgs(someMethodParam:0 param2:0).andDo(someBlock)

你可以做同样的期待。这种情况是作为主题启动请求进行存根。它是用OCMock 3.1.1测试的。

答案 4 :(得分:0)

尽管相当讨厌,但是使用期望来存储传递的块以便稍后在测试代码中调用的方法对我有用:

- (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);
}

答案 5 :(得分:0)

你可以这样做: src/

阅读更多:http://ocmock.org/reference/#argument-constraints