Xcode - 对网络调用进行单元测试

Xcode - Unit test a network call

我有以下代码,我想为其创建单元测试。我想检查 self.response 是否不为零

- (void)downloadJson:(NSURL *)url {
  // Create a download task.
  NSURLSessionDataTask *task = [[NSURLSession sharedSession]
        dataTaskWithURL:url
      completionHandler:^(NSData *data, NSURLResponse *response,
                          NSError *error) {
        if (!error) {
          NSError *JSONError = nil;
          NSDictionary *dictionary =
              [NSJSONSerialization JSONObjectWithData:data
                                              options:0
                                                error:&JSONError];
          if (JSONError) {
            NSLog(@"Serialization error: %@", JSONError.localizedDescription);
          } else {
            NSLog(@"Response: %@", dictionary);
            self.response = dictionary;
          }
        } else {
          NSLog(@"Error: %@", error.localizedDescription);
        }
      }];
  // Start the task.
  [task resume];
}

我目前所掌握的是

- (void)testDownloadJson {

  XCTestExpectation *expectation =
      [self expectationWithDescription:@"HTTP request"];
  [self.vc
      downloadJson:[NSURL URLWithString:@"a json file"]];

  [self waitForExpectationsWithTimeout:5
                               handler:^(NSError *error) {
                                 // handler is called on _either_ success or
                                 // failure
                                 if (error != nil) {
                                   XCTFail(@"timeout error: %@", error);
                                 } else {
                                   XCTAssertNotNil(
                                       self.vc.response,
                                       @"downloadJson failed to get data");
                                 }
                               }];
}

但这当然是不正确的。想知道是否有人可以帮助我了解如何编写此测试。

谢谢

难道downloadJson不提供一些完成处理程序,一个可以在异步调用完成时调用的块吗?有关通常如何使用 XCTestExpectation 的示例,请参见 。

通常你在完成处理程序中放置一个 [expectation fulfill] 以便 waitForExpectationsWithTimeout 知道它成功了。

坦率地说,无论如何,为您的 downloadJson 方法添加一个完成块可能会有用,所以您可能想要添加它。

- (void)downloadJson:(NSURL *)url completionHandler:(void (^)(NSDictionary *responseObject, NSError *error))completionHandler {
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (data) {
            NSError *JSONError = nil;
            NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&JSONError];
            if (dictionary) {
                // self.response = dictionary;  // personally, I wouldn't do this here, but just pass this back in the completion handler
                if (completionHandler) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completionHandler(dictionary, nil);
                    });
                }
            } else {
                // NSLog(@"Serialization error: %@", JSONError.localizedDescription); // I'd let caller do whatever logging it wants
                if (completionHandler) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completionHandler(nil, JSONError);
                    });
                }
            }
        } else {
            if (completionHandler) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completionHandler(nil, error);
                });
            }
            // NSLog(@"Error: %@", error.localizedDescription);  // I'd let caller do whatever logging it wants
        }
    }];

    [task resume];
}

在 Rob 发布的 link 之后,我现在有了这个并且可以正常工作

- (void)downloadJson:(NSURL*)url andCallback:(void (^)(NSDictionary*))callback
{
    // Create a download task.
    NSURLSessionDataTask* task = [[NSURLSession sharedSession] dataTaskWithURL:url
                                                             completionHandler:^(NSData* data,
                                                                                   NSURLResponse* response,
                                                                                   NSError* error) {
                                      if (!error)
                                      {
                                          NSError *JSONError = nil;

                                          NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data
                                                                                                     options:0
                                                                                                       error:&JSONError];
                                          if (JSONError)
                                          {
                                              NSLog(@"Serialization error: %@", JSONError.localizedDescription);
                                          }
                                          else
                                          {
                                              NSLog(@"Response: %@", dictionary);
                                              self.response = dictionary;
                                              callback(self.response);
                                          }
                                      }
                                      else
                                      {
                                          NSLog(@"Error: %@", error.localizedDescription);
                                      }
                                                             }];
    // Start the task.
    [task resume];
}

和测试

- (void)testDownloadJson
{
    XCTestExpectation* expectation = [self expectationWithDescription:@"HTTP request"];

    [self.vc downloadJson:[NSURL URLWithString:@"a json file"] andCallback:^(NSDictionary* returnData) {
        XCTAssertNotNil(returnData, @"downloadJson failed to get data");
        [expectation fulfill];
    }];

    [self waitForExpectationsWithTimeout:10.0 handler:nil];
}