【问题标题】:Using AFHTTPRequestOperation in XCTests在 XCTests 中使用 AFHTTPRequestOperation
【发布时间】:2015-01-17 13:26:04
【问题描述】:

我有以下测试用例代码:

- (void)testExample {
    // URL https://api.spotify.com/v1/search?q=album%3AJustified%20artist%3AJustin%20Timberlake&type=album


    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    [[AFHTTPRequestOperationManager manager] GET:@"https://api.spotify.com/v1/search"
                                      parameters:@{@"q":@"album:Justified artist:Justin Timberlake",
                                                   @"type":@"album"}
                                         success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                             dispatch_semaphore_signal(sem);
                                         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

                                         }
     ];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

    // This is an example of a functional test case.
    XCTAssert(YES, @"Pass");
}

我期待测试用例阻塞并等待 http 请求完成。 奇怪的是,即使 url 是有效的,AFHTTPRequestOperation 也永远不会到达成功块。 如果我在 XCTest 之外使用以下代码,则不会发生,将执行成功块。 有没有人见过这个?

【问题讨论】:

    标签: objective-c ios8 afnetworking xctest


    【解决方案1】:

    几个观察:

    1. 您的测试正在冻结,因为 AFNetworking 将其完成块分派到主队列。但是你用dispatch_semaphore_wait 阻塞了主线程,导致死锁。

      您可以通过将管理器的completionQueue 设置为用于测试的全局队列来解决此问题,从而消除由主线程上的信号量引起的死锁:

      - (void)testExample {
          dispatch_semaphore_t sem = dispatch_semaphore_create(0);
      
          AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
      
          manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      
          [manager GET:@"https://api.spotify.com/v1/search" parameters:@{@"q":@"album:Justified artist:Justin Timberlake", @"type":@"album"} success:^(AFHTTPRequestOperation *operation, id responseObject) {
              XCTAssert(YES, @"Pass"); // you might want more rigorous test of results here
      
              dispatch_semaphore_signal(sem);
          } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
              XCTFail(@"%@", error.localizedDescription);
      
              dispatch_semaphore_signal(sem);
          }];
      
          dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
      }
      
    2. 注意,现在人们会使用XCTestExpectation 来执行异步测试。这消除了对信号量的需求,巧合的是,也解决了死锁问题:

      - (void)testExample {
          XCTestExpectation *expectation = [self expectationWithDescription:@"asynchronous request"];
      
          AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
      
          [manager GET:@"https://api.spotify.com/v1/search" parameters:@{@"q":@"album:Justified artist:Justin Timberlake", @"type":@"album"} success:^(AFHTTPRequestOperation *operation, id responseObject) {
              XCTAssert(YES, @"Pass"); // you might want more rigorous test of results here
      
              [expectation fulfill];
          } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
              XCTFail(@"%@", error.localizedDescription);
      
              [expectation fulfill];
          }];
      
          [self waitForExpectationsWithTimeout:30.0 handler:nil];
      }
      
    3. 顺便说一句,无论您使用XCTestExpectation 还是信号量,请确保成功和失败块都满足期望/信号量。

    【讨论】:

    • 是的,我认为第二种解决方案对我有用。谢谢
    猜你喜欢
    • 2013-10-31
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多