服务器调用的完成和错误块的单元测试
Posted
技术标签:
【中文标题】服务器调用的完成和错误块的单元测试【英文标题】:Unit tests for completion & error blocks for server calls 【发布时间】:2015-08-24 10:29:51 【问题描述】:我正在尝试为我班级中的一种方法编写单元测试。此方法进行服务器调用并传递完成和错误块。我知道如何从测试类进行异步服务器调用,但我的疑问是如何测试使用完成和错误块进行服务器调用的方法。这里的目的是检查完成和错误块是否正确处理服务器响应。
如果有人以前这样做过,请指导。如果我的理解不正确,请纠正我。
以下是一种此类方法的示例。在这里,我想编写一个单元测试,它可以测试 'fetchItems' 方法的成功和错误处理情况。
- (void)fetchItems
__weak MyListController *aBlockSelf = self;
NSDictionary *aPostBody = @kMyCategoryId : self.categoryId;
// Fetch Items List From Server
self.requestHandler = [[MyRequestHandler alloc] initWithEndPoint:[kMyFetchQuickListCategoryProductsURLKey MyEndPoint] body:aPostBody container:self.view loadingOverlayTitle:nil successHandler:^(NSDictionary *iResponse)
if (iResponse)
aBlockSelf.isInfoData = [iResponse boolForKey:@"infoData"];
aBlockSelf.isTestEnabled = [iResponse boolForKey:@"enabled"];
NSArray *categoryData = iResponse[@"categoryData"];
NSArray *itemList = categoryData[0][@"items"];
NSSortDescriptor *aSortDescriptor = [[NSSortDescriptor alloc] initWithKey:kMySortOrderKey ascending:YES];
aBlockSelf.itemList = [MyListData quickListDataArray:[NSMutableArray arrayWithArray:[itemList sortedArrayUsingDescriptors:@[aSortDescriptor]]] withInventory:@10 andISInfoData: aBlockSelf.isInfoData];
[aBlockSelf fetchImages];
[aBlockSelf refresh];
andErrorHandler:^(NSString *iMessage, NSString *iKey, NSInteger iErrorCode, BOOL iIsNetworkError)
MySessionObject.selectedCategory = nil;
([aBlockSelf.alertView isVisible])
[aBlockSelf.alertView dismissWithClickedButtonIndex:self.alertView.cancelButtonIndex animated:YES];
aBlockSelf.alertView = nil;
if (iIsNetworkError)
aBlockSelf.alertView = [[MyUIAlertView alloc] initWithTitle:@"Error" message:iMessage cancelButtonTitle:@"OK" cancelButtonActionHandler:^
[aBlockSelf dismissViewController];
otherButtonTitle:nil andOtherButtonActionHandler:nil];
[aBlockSelf.alertView show];
aBlockSelf.navigationItem.rightBarButtonItem.enabled = YES;
aBlockSelf.navigationItem.leftBarButtonItem.enabled = YES;
];
[self.requestHandler executeRequest];
【问题讨论】:
一些示例代码会很有用。 @TomaszBąk:感谢您的回复。我仍然对确切的实施有疑问。我添加了一个示例方法,我正在尝试为其编写测试用例。请您参考这个方法解释一下。 【参考方案1】:一般来说,如果你的模型中有一个服务器请求,你应该用一个新的对象或抽象接口将它分开。多亏了这一点,在测试时,您可以存根服务器以发送固定响应。假设您已将请求分开发送到此对象:
@interface ServerCommuncation : NSObject
- (void)request:(id)request completion:(void (^)(NSError *error))completion;
@end
现在在您的单元测试中,您可以注入您的存根:
@interface ServerCommuncationStub : ServerCommunication
@property (nonatomic, copy) void (^completion)(NSError *error);
@end
@implementation ServerCommuncationStub
- (void)request:(id)request completion:(void (^)(NSError *error))completion
self.completion = completion;
并且你在适合你的时候调用完成:
ServerCommuncationStub *stub = [ServerCommuncationStub new];
Model *model = [[Model alloc] initWithServerCommunication:stub];
[model request];
stub.completion(nil);
更好的方法是使用模拟库。我个人使用 OCMockito。不用子类化也可以达到同样的效果:
ServerCommuncation *mock = mock([ServerCommuncation class]);
Model *model = [[Model alloc] initWithServerCommunication:mock];
[model request];
MKTArgumentCaptor *captor = [MKTArgumentCaptor new];
[verify(mock) request:anyting() completion:[captor capture]];
void(^block)(NSError *error) = [captor value];
block(nil);
您可以在Refactoring 和Working Effectively with Legacy Code 中找到许多关于使您的代码可测试的有用信息
【讨论】:
以上是关于服务器调用的完成和错误块的单元测试的主要内容,如果未能解决你的问题,请参考以下文章