web-dev-qa-db-ja.com

プリミティブをOCMockのスタブに渡す

OCMockを使用してiPhoneのプロジェクトをテストする方法を学んでおり、次のシナリオがあります。getHeightAtX:andY:メソッドを使用するHeightMapクラスと、HeightMapを使用するRenderクラスです。いくつかのHeightMapモックを使用してRenderのユニットテストを試みています。これは機能します:

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]];

しかし、これにより2つのコンパイル警告が発生します。

警告:'getHeightAtX:andY:'の引数1を渡すと、キャストなしでポインタから整数になります

およびランタイムエラー:

予期しないメソッドが呼び出されました:'getHeightAtX:0 andY:0 stubbed: getHeightAtX:15545040 andY:15545024'

何が足りないのですか?このモックにanyValueを渡す方法が見つかりませんでした。

30
Eduardo Costa

OCMockは現在、プリミティブ引数の緩いマッチングをサポートしていません。これをサポートするための潜在的な変更についての議論があります OCMockフォーラムで 、それは行き詰まっているようですが。

私が見つけた唯一の解決策は、渡されるプリミティブ値がわかるようにテストを構造化することですが、理想からはほど遠いです。

18

この質問が出されてからしばらく経ちましたが、私は自分でこの問題に遭遇し、どこにも解決策を見つけることができませんでした。 OCMockはignoringNonObjectArgsをサポートするようになったため、expectの例は次のようになります。

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

5は実際には何もしません。フィラー値だけです。

49
Andrew Park

代わりに OCMockito を使用してください。

プリミティブ引数マッチングをサポートします。

たとえば、あなたの場合:

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

Andrew Parkの回答に加えて、もう少し一般的で見栄えの良いものにすることができます。

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

あなたはそれをそのように使うことができます:

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

あなたは期待するために同じことをすることができます。このケースは、トピックスターターリクエストとしてスタブするためのものです。 OCMock3.1.1でテストされました。

1
Alex

あなたはこのようにすることができます:id chunk = OCMClassMock([Chunk class]) OCMStub([chunk ignoringNonObjectArgs] getHeightAtX:0 andY:0]])

続きを読む: http://ocmock.org/reference/#argument-constraints

0
Tan Vu

かなりハッキーですが、期待値を使用して渡されたブロックを格納し、後でテストコードで呼び出すというアプローチは、私にとってはうまくいきました。

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