我正在关注测试驱动的 iOS 开发中的示例,在一种情况下,有一个单元测试可确保委托获得错误方法的“简化”版本。因此,这里不涉及太多细节,而是相关对象:
- 通信器:负责进行网络调用的对象
- manager:指示通信器进行调用,然后将结果推送给其委托。
- 委托:符合
StackOverflowManagerDelegate
协议的经理委托。得到结果并处理它。
所以这就是测试:
@implementation QuestionCreationTests
{
@private
StackOverflowManager *mgr;
}
- (void)testErrorReturnedToDelegateIsNotErrorNotifiedByCommunicator {
MockStackOverflowManagerDelegate *delegate =
[[MockStackOverflowManagerDelegate alloc] init];
mgr.delegate = delegate;
NSError *underlyingError = [NSError errorWithDomain: @"Test domain"
code: 0 userInfo: nil];
[mgr searchingForQuestionsFailedWithError: underlyingError];
XCTAssertFalse(underlyingError == [delegate fetchError],
@"Error should be at the correct level of abstraction");
}
这是searchingForQuestionsFailedWithError
StackOverflowManager 中的实现,其中管理器简单地将通信器返回的原始错误简化并将简化的版本发送给委托。
- (void)searchingForQuestionsFailedWithError:(NSError *)error {
NSDictionary *errorInfo = [NSDictionary dictionaryWithObject: error
forKey: NSUnderlyingErrorKey];
NSError *reportableError = [NSError
errorWithDomain: StackOverflowManagerSearchFailedError
code: StackOverflowManagerErrorQuestionSearchCode
userInfo:errorInfo];
[delegate fetchingQuestionsOnTopic: nil
failedWithError: reportableError];
}
作者建议为此工作..我们实际上必须为经理委托创建一个模拟对象,如下所示:
@interface MockStackOverflowManagerDelegate : NSObject <StackOverflowManagerDelegate>
@property (strong) NSError *fetchError;
@end
@implementation MockStackOverflowManagerDelegate
@synthesize fetchError;
- (void)fetchingQuestionsOnTopic: (Topic *)topic
failedWithError: (NSError *)error {
self.fetchError = error;
}
@end
这是声明StackOverflowManagerDelegate
:
@protocol StackOverflowManagerDelegate <NSObject>
- (void)fetchingQuestionsOnTopic: (Topic *)topic
failedWithError: (NSError *)error {
@end
问题:我一直在浏览本书的所有示例,并尝试使用 OCMock 而不是作者正在做的手动制作的示例。(我只是认为这会少很多时间)。到目前为止一切正常..但我被困在这里..我如何伪造一个名为fetchError
委托的属性?这就是我现在所拥有的:
- (void)testErrorReturnedToDelegateIsNotErrorNotifiedByCommunicator {
id <StackOverflowManagerDelegate> delegate =
[OCMockObject mockForProtocol:@protocol(StackOverflowManagerDelegate)];
mgr.delegate = delegate;
NSError *underlyingError = [NSError errorWithDomain: @"Test domain"
code: 0 userInfo: nil];
[mgr searchingForQuestionsFailedWithError: underlyingError];
// compiler error here: no known instance method for selector 'fetchError'
XCTAssertFalse(underlyingError == [mgr.delegate fetchError], @"error ");
}
在经理的胆量中,经理调用fetchingQuestionsOnTopic
了代表..我知道我可以通过使用 [[[delegate stub] andCall:@selector(differentMethod:) onObject:differentObject] fetchingQuestionsOnTopic:[OCMArg any]]
where differentMethod
would do what I want it do..我只是不知道如何处理以下结果differentMethod
:我不知道不知道如何将其存储在委托的模拟属性中。
更新:作为以下答案的后续..这是单元测试的实现,可确保委托仍然可以使用底层错误:
- (void)testErrorReturnedToDelegateDocumentsUnderlyingError {
MockStackOverflowManagerDelegate *delegate =
[[MockStackOverflowManagerDelegate alloc] init];
mgr.delegate = delegate;
NSError *underlyingError = [NSError errorWithDomain: @"Test domain"
code: 0 userInfo: nil];
[mgr searchingForQuestionsFailedWithError: underlyingError];
XCTAssertEqual([[[delegate fetchError] userInfo]
objectForKey: NSUnderlyingErrorKey], underlyingError,
@"The underlying error should be available to client code");
}
这是它的 OCMock 版本:
- (void)testErrorReturnedToDelegateDocumentsUnderlyingErrorOCMock {
id delegate =
[OCMockObject mockForProtocol:@protocol(StackOverflowManagerDelegate)];
mgr.delegate = delegate;
NSError *underlyingError = [NSError errorWithDomain: @"Test domain"
code: 0 userInfo: nil];
[[delegate expect] fetchingQuestionsFailedWithError:
[OCMArg checkWithBlock:^BOOL(id param) {
return ([[param userInfo] objectForKey:NSUnderlyingErrorKey] == underlyingError);
}]];
[mgr searchingForQuestionsFailedWithError: underlyingError];
[delegate verify];
}