OCMock [OCMAnyConstraint isProxy]:发送到已解除分配的实例的消息,发生了什么?



我正在尝试对一个对象进行简单的模拟

HTAppleWatchDevice * shared = [[HTAppleWatchDevice alloc] init];
id watchMock = [OCMockObject partialMockForObject:shared];
[deviceManager setAppleWatchDevice:watchMock];
void (^replyDict)(NSDictionary*) = ^void(NSDictionary* response){};
[[watchMock expect] dataReturnedFromServer:[OCMArg isNotNil] ofType:[OCMArg any]];
[watchMock handleWatchKitExtensionRequest:request reply:replyDict];
[watchMock verifyWithDelay:10];

事实上,调用了预期的方法,但我得到了这种错误,这取决于第二个OCMArg:

〔OCMAnyConstraint isProxy〕:消息发送到已解除分配的实例0x7f954608b630

我确实尝试过将预期的调用FIRST放在handleWatchKitExtensionRequest:reply:中,使用伪数据,但发生了完全相同的错误。

[self dataReturnedFromServer:@[] ofType:[self supportedMIMETypes].firstObject];

更新:该类使用了反应可可,它交换了对象的类,我怀疑可能由于重叠的类交换而发生了交互。我会给它贴标签,直到我把它数出来。

举个例子,我注释掉了验证线

[[watchMock expect] dataReturnedFromServer:[OCMArg isNotNil] ofType:[OCMArg any]];
[watchMock handleWatchKitExtensionRequest:request reply:replyDict];
//[watchMock verifyWithDelay:10];

但另一个例外出现了,一旦前一个watchMock被解除锁定:

RACKVOTrampoline.m:处理方法,异常,下一次测试开始时…:

[target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];

错误:-[HTAppleWatchDeviceTest nameOfNextTest]:失败:捕获到"NSRangeException","无法从中删除密钥路径"delegate"的观察器,因为它未注册为观察器。">

有什么想法吗?

好吧,让我展示一下我通过方法Swizzling找到的解决方法——尽管我不会接受它。

HTAppleWatchDeviceTest.m

static XCTestExpectation* roundTripExpectation = nil; //static var is avail from this FILE
-(void) testPerceiveActuateRoundTrip{
roundTripExpectation = [self expectationWithDescription:@"should return data"];
HTAppleWatchDevice * shared = [deviceManager appleWatchDevice];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//steps
//1 identify old and new selectors
SEL oldSelector = @selector(dataReturnedFromServer:ofType:);
SEL newSelector = @selector(HTTest_dataReturnedFromServer:ofType:);
//2 get old method for old selector
Method oldMethod = class_getInstanceMethod([shared class], oldSelector);
//3 get new implementation for new selector
Method newMethod = class_getInstanceMethod([self class], newSelector);
//4 set new implementation for old selector -- might fail
BOOL addedFine = class_addMethod([shared class], oldSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
//5 set old implementation for new selector, used to continue normal execution
class_addMethod([shared class], newSelector, method_getImplementation(oldMethod), method_getTypeEncoding(oldMethod));
//6 swap new and old implementations for HTAppleWatchDevice, if not already set above
//NOTE: will NOT effect step 5, as implementation was set directly. WILL effect [self HTTest_dataReturnedFromServer:ofType:] -> oldImplementation (on HTAppleWatchDevice), but NBD
if (!addedFine){
method_exchangeImplementations(oldMethod, newMethod);
}
});
void (^replyDict)(NSDictionary*) = ^void(NSDictionary* response){};
[shared handleWatchKitExtensionRequest:request reply:replyDict];
[self waitForExpectationsWithTimeout:10 handler:nil];
roundTripExpectation = nil;
}
//this method will ONLY be called with [self class] == HTAppleWatchDevice
-(void)HTTest_dataReturnedFromServer:(NSArray*)activations ofType:(NSString*)type{
[self HTTest_dataReturnedFromServer:activations ofType:type];
[testPerceiveActuateRoundTripExpectation fulfill];
}

最新更新