Last active
October 10, 2017 15:37
-
-
Save Ashton-W/19d0025e3ef43ae4c386 to your computer and use it in GitHub Desktop.
Implementation of an XCTestExpectation for delegate calls. More here http://www.ashton-w.net/2016/01/23/Asynchronous-Testing.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <XCTest/XCTest.h> | |
NS_ASSUME_NONNULL_BEGIN | |
@interface ExpectationDelegateProxy : NSProxy | |
@property (nonatomic) SEL selector; | |
@property (nonatomic) Protocol *protocol; | |
@property (nonatomic) XCTestExpectation *expectation; | |
- (instancetype)initWithProtocol:(Protocol *)protocol selector:(SEL)selector expectation:(XCTestExpectation *)expectation; | |
@end | |
NS_ASSUME_NONNULL_END |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "ExpectationDelegateProxy.h" | |
#import <objc/runtime.h> | |
#import <objc/protocol.h> | |
@implementation ExpectationDelegateProxy | |
- (instancetype)initWithProtocol:(Protocol *)protocol selector:(SEL)selector expectation:(XCTestExpectation *)expectation | |
{ | |
NSParameterAssert(protocol); | |
NSParameterAssert(selector); | |
NSParameterAssert(expectation); | |
_protocol = protocol; | |
_selector = selector; | |
_expectation = expectation; | |
return self; | |
} | |
#pragma mark - NSProxy | |
- (void)forwardInvocation:(NSInvocation *)invocation | |
{ | |
if (sel_isEqual(self.selector, invocation.selector)) { | |
[self.expectation fulfill]; | |
} | |
} | |
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector | |
{ | |
// taken from OCMock's OCProtocolMockObject | |
struct { BOOL isRequired; BOOL isInstance; } opts[4] = { {YES, YES}, {NO, YES}, {YES, NO}, {NO, NO} }; | |
for(int i = 0; i < 4; i++) | |
{ | |
struct objc_method_description methodDescription = protocol_getMethodDescription(self.protocol, aSelector, opts[i].isRequired, opts[i].isInstance); | |
if(methodDescription.name != NULL) | |
return [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; | |
} | |
return nil; | |
} | |
- (BOOL)conformsToProtocol:(Protocol *)aProtocol | |
{ | |
return protocol_conformsToProtocol(self.protocol, aProtocol); | |
} | |
- (BOOL)respondsToSelector:(SEL)selector | |
{ | |
return ([self methodSignatureForSelector:selector] != nil); | |
} | |
- (BOOL)isKindOfClass:(Class)aClass | |
{ | |
return (self.class == aClass); | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import XCTest | |
import ObjectiveC.runtime | |
var ExpectationDelegateProxyAssociationKey: UInt8 = 0 | |
extension XCTestExpectation { | |
var delegateProxy: ExpectationDelegateProxy { | |
get { | |
return objc_getAssociatedObject(self, &ExpectationDelegateProxyAssociationKey) as! ExpectationDelegateProxy | |
} | |
set { | |
objc_setAssociatedObject(self, &ExpectationDelegateProxyAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) | |
} | |
} | |
} | |
extension XCTestCase { | |
func expectationForDelegate(delegate: Protocol, selector: Selector) -> XCTestExpectation { | |
let expectation = expectationWithDescription("\(selector) called on \(NSStringFromProtocol(delegate))") | |
expectation.delegateProxy = ExpectationDelegateProxy(withProtocol: delegate, selector: selector, expectation: expectation); | |
return expectation; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment