【发布时间】:2014-04-29 21:40:09
【问题描述】:
我正在尝试使用 XCTest 在 XCode 5 中对使用 AFNEtworking 的类进行单元测试。我遇到的问题是我的 AFHTTPRequestOperation 的完成块永远不会被执行。我认为这是运行单元测试的 XCode 和 AFNetworking 的调度队列之间的一些脱节。以下测试用例通过但从未到达完成块中的 NSLog 语句(没有日志输出,也没有捕获在这些语句上设置的断点)。相同的代码在单元测试之外工作。有谁知道如何解决这个问题?我使用 Nocilla 模拟实际请求,结果与使用真实服务器重新调整有效响应的结果相同?
已编辑以使测试失败并记录块中设置的变量
- (void)setUp
{
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
[[LSNocilla sharedInstance] start];
stubRequest(@"POST", @"http://www.example.com/module/api/ping").
andReturn(200).
withHeaders(@{@"Content-Type": @"application/json"}).
withBody(@"{\"success\":true}");
stubRequest(@"GET", @"http://www.example.com/module/api/ping?testkey=testval").
andReturn(200).
withHeaders(@{@"Content-Type": @"application/json"}).
withBody(@"{\"success\":true}");
}
- (void)tearDown
{
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
[[LSNocilla sharedInstance] stop];
[[LSNocilla sharedInstance] clearStubs];
}
- (void)testSanity
{
AFSecurityPolicy *policy = [[AFSecurityPolicy alloc] init];
//[policy setAllowInvalidCertificates:YES];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.example.com/module/api/ping"]];
//manager.operationQueue = [NSOperationQueue mainQueue];
[manager setSecurityPolicy:policy];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
__block id resObj = nil;
__block id resError = nil;
AFHTTPRequestOperation *req = [manager POST:@"http://www.example.com/module/api/ping"
parameters:[NSDictionary dictionaryWithObject:@"testval" forKey:@"testkey"]
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"Response: %@", responseObject);
resObj = responseObject;
return;
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
resError = error;
return;
}];
[req waitUntilFinished];
NSLog(@"req.status: %d", req.response.statusCode);
NSLog(@"req.responseObj: %@", req.responseObject);
XCTAssertTrue(req.isFinished);
NSLog(@"resObj: %@", resObj);
NSLog(@"resError: %@", resError);
XCTAssertEqual([[req.responseObject objectForKey:@"success"] boolValue], YES);
XCTAssertEqual([[resObj objectForKey:@"success"] boolValue], YES);
}
控制台输出
测试用例“-[AppSupportTests testSanity]”已启动。 2014-04-29 16:45:07.424 xctest[72183:303] req.status: 200 2014-04-29 16:45:07.424 xctest[72183:303] req.responseObj: { 成功 = 1; } 2014-04-29 16:45:07.424 xctest[72183:303] resObj: (null) 2014-04-29 16:45:07.425 xctest[72183:303] resError: (null) /Users/jlujan/Code/AppSupport/AppSupportTests/AppSupportTests.m:114: 错误:-[AppSupportTests testSanity] : (([[resObj objectForKey:@"success"] boolValue]) 等于 (__objc_yes)) 失败:(" NO") 不等于 ("YES") 测试用例“-[AppSupportTests testSanity]”失败(0.003 秒)。【问题讨论】:
-
一旦后台操作完成,它可能会调用
waitUntilFinished,但这将是在调用回调之前。你可以尝试使用semaphores 到wait 直到你有signaled -
对于异步测试我推荐Expecta顺便说一句。然后,您可以执行
expect([[req.responseObject objectForKey:@"success"] boolValue]).will.beTruthy();之类的操作(尽管我不喜欢beTruthy语法!)。您只需确保设置了适当的超时时间[Expecta setAsynchronousTestTimeout:15];//seconds -
这只是一个健全性检查,以确保我的实际代码没有导致它。使用这里的信号量示例stackoverflow.com/questions/20476957/…,它会永远挂起。无论哪种方式,我都不能在我的实际代码中使用信号量方法。
-
@Rich,感谢您指向 Expecta。从长远来看,这比找出调度队列向南的方向更好的解决方案。
标签: ios xcode afnetworking-2 xctest