31

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

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

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

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

但这会引发两个编译警告:

警告:传递参数 1'getHeightAtX:andY:'从指针生成整数而不进行强制转换

和运行时错误:

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

我错过了什么?我发现没有办法将 a 传递anyValue给这个模拟。

4

6 回答 6

50

自从提出这个问题以来已经有一段时间了,但我自己遇到了这个问题并且在任何地方都找不到解决方案。OCMock 现在支持ignoringNonObjectArgs,所以一个例子expect

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

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

于 2013-11-08T01:00:27.157 回答
18

OCMock 目前不支持原始参数的松散匹配。在 OCMock 论坛上有一个关于支持这一点的潜在变化的讨论,尽管它似乎已经停滞不前。

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

于 2011-06-13T14:47:09.277 回答
2

请改用OCMockito

它支持原始参数匹配。

例如,在您的情况下:

id chunk = mock([Chunk class]);
[[given([chunk getHeightAtX:0]) withMatcher:anything() forArgument:0] willReturnInt:0];
于 2013-05-23T07:35:25.677 回答
1

除了Andrew Park的回答之外,您还可以让它更通用、更美观:

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

你可以这样使用它:

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

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

于 2014-12-18T00:31:27.787 回答
1

你可以这样做: id chunk = OCMClassMock([Chunk class]) OCMStub([chunk ignoringNonObjectArgs] getHeightAtX:0 andY:0]])

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

于 2018-05-04T07:57:52.373 回答
0

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

- (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);
}
于 2017-05-04T23:49:20.003 回答