1

I have the following code that I'm wanting to create a unit test for. I want to check if self.response is not nil

- (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];
}

what I have so far is

- (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");
                                 }
                               }];
}

But of course this isn't correct. Wondering if someone could help me get the idea on how to write this test.

Thanks

user2812463
  • 265
  • 5
  • 14

2 Answers2

4

Does downloadJson not provide some completion handler, a block that can be called when the asynchronous call finishes? See How do I unit test HTTP request and response using NSURLSession in iOS 7.1? for an example of how one generally uses XCTestExpectation.

Usually you put a [expectation fulfill] inside the completion handler so that the waitForExpectationsWithTimeout knows that it succeeded.

Frankly, having a completion block for your downloadJson method would probably be useful, anyway, so you might want to add that.

- (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];
}
Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
2

following the link posted by Rob, I now have this and it works

- (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];
}

and the test

- (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];
}
user2812463
  • 265
  • 5
  • 14