OCMock: Measuring protocols with the exception of additional methods

I use OCMock to create mocks in my tests for my iOS application, and I would like to create mocks protocols that do not implement all the optional methods.

If it’s not clear what I mean ... here is some code:

// 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)]; 
+7
source share
2 answers

I hit this limitation too. The main idea is to override respondsToSelector : (which CANNOT be reliably ridiculed by OCMock).

I made the following class that does this for you. Then you can use it as follows:

extend GCOCMockOptionalMethodSupportingObject and implement your protocol

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

If you do not call markSelectorAsImplemented , then your classBeingTested will receive NO for respondsToSleectorForThatMethod

I posted the code here. I use this for a great effect. Thanks to jer at #iphonedev for disabling me along the way (overriding respondsToSelector was his idea, I did some crazy runtime methods - this is a much cleaner concept).

here is the code

 /** * 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
source

The simplest thing is to create a class containing the selector that you want to implement. There should be no implementation. Then you create the mock class of this class instead of the protocol layout and use it in exactly the same way.

For example:

 @interface MyAwesomeImplementation : NSObject <MyAwesomeProtocol> - (void)doThatRequiredThing; @end @implementation MyAwesomeImplementation - (void)doThatRequiredThing {} @end id mock = OCMStrictClassMock([MyAwesomeImplementation class]); 
+1
source

All Articles