2012-08-12 7 views
7

iOSアプリケーション用のテストでモックを作成するためにOCMockを使用しています。オプションのメソッドをすべて実装していないモックを作成したいと思います。OCMock:オプションのメソッドを除外した模擬プロトコル

それは私が何を意味するかはっきりしていない場合は...ここにいくつかのコードは次のとおりです。

// Protocol definition 
@protocol MyAwesomeProtocol 
    - (void)doThatRequiredThing; 
    @optional 
    - (void)doThatOptionalThing; 
@end 

... 

// In a test 
id mock = [OCMockObject mockObjectForProtocol:@protocol(MyAwesomeProtocol)]; 

// This should return YES: 
[mock respondsToSelector:@selector(doThatRequiredThing)]; 
// This should return NO: 
[mock respondsToSelector:@selector(doThatOptionalThing)]; 
+1

私はお返しに質問してみましょう。オプションのメソッドに応答するかどうかを尋ねられたときに、なぜモックはNOを返しますか?その方法は結局のところプロトコルの一部です。 プロトコルを実装するクラスをモックすることは可能でしょうか?そのクラスがオプションのメソッドを実装していない場合、モックはあなたが期待することを行います。 –

+0

なぜなら、オプションのデリゲートメソッドを実装していないデリゲートがある場合、クラスが正しく動作することをテストしたいからです。 – extremeboredom

答えて

1

私も、この制限をヒット。基本的な考え方は、respondsToSelectorをオーバーライドすることです(OCMockで確実に嘲笑されることはありません)。

私はあなたのためにこれを行う次のクラスを作った。次のようにあなたはそれを使用することができます :

GCOCMockOptionalMethodSupportingObjectを拡張し、あなたがmarkSelectorAsImplementedを呼び出さない場合は、お使いのclassBeingTestedがNO respondsToSleectorForThatMethod

のために私が置かれているでしょう

@interface GCTestDelegate : GCOCMockOptionalMethodSupportingObject <GCDelegate> 
@end 

@implementation GCTestDelegate 

//required methods 
- (void)requiredMethod{ 
} 
@end 

// create your testdelegate 
self.classBeingTested.delegate = [OCMock partialMockForObject:[GCTestDelegate new]]; 
[self.classBeingTested.delegate markSelectorAsImplemented:@selector(optionalMethod:)]; 
[[self.classBeingTested.delegate expect] optionalMethod:self.classBeingTested]; 
[self.classBeingTested doSomethingThatwillCheckIfYourDelegateRespondsToYourOptionalMethod]; 

あなたのプロトコルを実装しますそれのためのコードはここにあります。私はこれを有効に使っています。 #iphonedevのjerさんに感謝します(respondsToSelectorのオーバーライドは彼のアイデアでしたが、私はいくつかの狂気のランタイムメソッドを追加していました - これははるかにクリーンなmethinkです)。

ここ一番簡単な方法は、あなたが実現したいセレクタを含むクラスを作成することで、コード

/** 
* This class is specifically useful and intended for testing code paths that branch 
* pending implementation of optional methods. 
* OCMock does not support mocking of protocols with unimplemented optional methods. 
* Further compounding the issue is the fact that OCMock does not allow mocking of 
* respondsToSelector (in fact, it does but the behaviour is undefined), 
* As such this class can be extending to implement a given protocol, the methods can be mocked/expected 
* as normal, but in addition we can tell the class to report it conforms to a protocol method or not. 
* 
*/ 
@interface GCOCMockOptionalMethodSupportingObject : NSObject 

- (void)markSelectorAsImplemented:(SEL)aSelector; 
- (void)unmarkSelectorAsImplemented:(SEL)aSelector; 


@end 

#import "GCOCMockOptionalMethodSupportingObject.h" 


@interface GCOCMockOptionalMethodSupportingObject() 
@property(nonatomic, strong) NSMutableArray *implementedSelectors; 

@end 

@implementation GCOCMockOptionalMethodSupportingObject { 

} 
////////////////////////////////////////////////////////////// 
#pragma mark init 
////////////////////////////////////////////////////////////// 

- (id)init { 
    self = [super init]; 
    if (self) { 
     self.implementedSelectors = [NSMutableArray array]; 
    } 

    return self; 
} 

////////////////////////////////////////////////////////////// 
#pragma mark public api 
////////////////////////////////////////////////////////////// 


- (void)markSelectorAsImplemented:(SEL)aSelector { 
    if (![self isImplemented:aSelector]) { 
     [self.implementedSelectors addObject:NSStringFromSelector(aSelector)]; 
    } 
} 


- (void)unmarkSelectorAsImplemented:(SEL)aSelector { 
    for (NSString *selectorValue in [self.implementedSelectors mutableCopy]) { 
     SEL storedSelector = NSSelectorFromString(selectorValue); 
     if (sel_isEqual(aSelector, storedSelector)) { 
      [self.implementedSelectors removeObject:selectorValue]; 
      break; 
     } 
    } 
} 


////////////////////////////////////////////////////////////// 
#pragma mark private impl 
////////////////////////////////////////////////////////////// 


- (BOOL)isImplemented:(SEL)aSelector { 
    for (NSString *selectorValue in self.implementedSelectors) { 
     SEL storedSelector = NSSelectorFromString(selectorValue); 
     if (sel_isEqual(aSelector, storedSelector)) { 
      return YES; 
     } 
    } 
    return NO; 
} 

////////////////////////////////////////////////////////////// 
#pragma mark overridden 
////////////////////////////////////////////////////////////// 

- (BOOL)respondsToSelector:(SEL)aSelector { 
    if ([self isImplemented:aSelector]) { 
     return YES; 
    } else { 
     return [super respondsToSelector:aSelector]; 
    } 
} 

@end 
1

です。実装する必要はありません。次に、プロトコルモックの代わりにそのクラスのクラスモックを作成し、同じ方法で使用します。例えば

@interface MyAwesomeImplementation : NSObject <MyAwesomeProtocol> 
- (void)doThatRequiredThing; 
@end 
@implementation MyAwesomeImplementation 
- (void)doThatRequiredThing {} 
@end 

id mock = OCMStrictClassMock([MyAwesomeImplementation class]); 
関連する問題