我正在使用 OCMock 在我的 iOS 应用程序测试中创建模拟,我想创建不实现所有可选方法的协议(protocol)模拟。
如果不清楚我的意思...这里有一些代码:
// 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)];
最佳答案
我也遇到了这个限制。基本思想是覆盖 respondsToSelector
:(OCMock 不能可靠地模拟它)。
我制作了以下类(class)来为您完成这项工作。 然后您可以按如下方式使用它:
扩展 GCOCMockOptionalMethodSupportingObject
,并实现您的协议(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];
如果您不调用 markSelectorAsImplemented
,那么您的 classBeingTested
将针对 respondsToSleectorForThatMethod
获取 NO
我已经把它的代码放在这里了。我用这个效果很好。感谢 #iphonedev 上的 jer 让我走上了这条路(覆盖 respondsToSelector
是他的想法,我正在做一些疯狂的运行时方法添加 - 这是更清晰的方法)。
这是代码
/**
* 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
关于objective-c - OCMock:模拟协议(protocol),排除可选方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11923942/