【问题标题】:AFNetworking 2.0 and Unit TestAFNetworking 2.0 和单元测试
【发布时间】: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,但这将是在调用回调之前。你可以尝试使用semaphoreswait 直到你有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


【解决方案1】:

根据 cmets 中的讨论,我们发现 waitUntilFinished is once the background operation is complete,并且它不会等到调用完成块之后。

有一个更好的异步测试框架 - Expecta
然后代替调用:

XCTAssertTrue(req.isFinished);
XCTAssertEqual([[resObj objectForKey:@"success"] boolValue], YES);

你可以这样做:

expect(req.isFinished).will.beTruthy();
expect([[resObj objectForKey:@"success"] boolValue]).will.beTruthy();

lots of other matchers,只要确保在+setUp 方法中设置timeout+[Expecta setAsynchronousTestTimeout:]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多