2013-05-13 8 views
26

次のようなメソッドシグネチャを想定:OCMockはブロックパラメータを実行できますか?

- (void)theMethod:(void(^)(BOOL completed))completionBlock; 

Iメソッドが呼び出される保証するために、このメソッドシグネチャを模擬し、ちょうど完了ブロックを呼び出したいです。 this oneのような他の投稿から、メソッド呼び出しを模擬してブロックを受け入れることはできますが、ブロックを実行することはできません。私は、使用できるかもしれないAndDoメソッドがあることを知っていますが、ブロックを渡して実行する方法を理解することはできません。

アイデア?

ありがとうございました。

答えて

31

あなたのモックメソッドが呼び出されたときに呼び出される別のブロックを渡すために、このような[[mock stub] andDo:]を使用することができます。

void (^proxyBlock)(NSInvocation *) = ^(NSInvocation *invocation) { 
    void (^passedBlock)(BOOL); 
    [invocation getArgument: &passedBlock atIndex: 2]; 
}; 
[[[mock stub] andDo: proxyBlock] theMethod:[OCMArg any]]; 

ブロックは、すべて使用される引数を照会することができ、そこからNSInvocationインスタンスを取得します。最初の引数は、インデックス0と1にselfと_cmdがあるので、インデックス2にあることに注意してください。

+4

のために更新され、おそらく、あなたはブロックを呼び出すためにandDoにpassedBlock(YES)を行うと思います。 –

+0

ありがとう!最後にそれがうまくいったので、サンプルにコールするコードを書いてください。 passedBlock(YES) – Denis

16

EDIT 2: 代わりにhttps://stackoverflow.com/a/32945785/637641を使用してください。

andDo:を使用すると問題はありませんが、私は個人的には[OCMArg checkWithBlock:]を好きです。

[[mock expect] theMethod:[OCMArg checkWithBlock:^BOOL(id param) 
{ 
    void (^passedBlock)(BOOL) = param; 
    // Normally I set some expectations here and then call the block. 
    return YES; 
}]]; 

// Code to test 

[mock verify]; 

[模擬スタブ]も使用できますが、私はtheMethodが呼び出されていることを確認することをお勧めします。

EDIT 1

OCMock 3バージョン:

OCMExpect([mock theMethod:[OCMArg checkWithBlock:^BOOL(void (^passedBlock)(BOOL)) 
{ 
    // call the block... 
    return YES; 
}]]); 

// Code to test 

OCMVerify(mock); 
+3

この目的のためにcheckWithBlockを使用することには2つの問題があります。一つは、 'ignoringNonObjectArgs'がtrueで、オブジェクトparamがブロックparamの前に来ると、OCMockの現在のバージョンはオブジェクトパラメータのチェックを止めるということです。第2の問題は、checkWithBlock呼び出しの後で引数の制約が失敗した場合、完了ブロックが誤って呼び出されることです。ブロックを呼び出す信頼できる唯一の方法は 'andDo:'を使うことです。 'checkWithBlock'はNSInvocationのパラメータハンドハンドリングを邪魔しないので、これはあまりにも悪いことです。 – phatmann

8

これは今OCMock 3.2でサポートされています。 [OCMArg invokeBlock][OCMArg invokeBlockWithArgs:...]を使用して、スタブ付きメソッドの引数として渡されたブロックを呼び出すことができます。

+1

あなたの使い方の例を提供できるなら、非常に便利です。 – singingAtom

+1

@singingAtomチェックアウト[OCMockテスト](https://github.com/erikdoe/ocmock/blob/master/Source/OCMockTests/OCMockObjectTests.m#L618-L711)。私はGithub [ここ](https://github.com/SteveFortune/ocmock-block-tests)にいくつかの例を載せています。これらは少し古くなっています。 'OCMDefault'が' [OCMArg defaultValue] 'に変更されました。 – sf13579

+0

これは 'NSInvocation'に関連する頭痛を避けるため、これまでのところ最高の答えです。 –

5

andDo:ブロックを使用することがありますが、ほとんどの場合、[OCMArg invokeBlock]または[OCMArg invokeBlockWithArgs:]を使用できます。あなたの例では

あなたは引数を気にしない場合は、次の
を行うことができます。

// Call block with YES. 
OCMStub([mock theMethod:([OCMArg invokeBlockWithArgs:@YES, nil])]; 

nil終了:あなたは、特定の引数を送信する場合は

// Call block with default arguments. 
OCMStub([mock theMethod:[OCMArg invokeBlock]]; 

このメソッドに複数の引数を渡すことができるからです。 さらに、式全体をかっこで囲む必要があります。

OCMock documentationで詳しく読むことができます。

2

このスヴェンの答えはOCMock 3.

OCMStub([myMock myMethodWithMyBlock:[OCMArg any]]).andDo(^(NSInvocation *invocation) { 
    void (^passedBlock)(BOOL myFirstArgument, NSError *mySecondArgument); 
    [invocation getArgument: &passedBlock atIndex: 2]; 
    passedBlock(YES, nil); 
}); 
関連する問題