Question

I have an iOS app I'm working on, which connects to a third-party web service. I have around 50 different calls, and want to write unit tests using Kiwi, but I have no idea where to start.

As I'm not responsible for the API, I need to just check that my calls are pointing to the correct URL, using the correct GET or POST method.

Is there any way to test this properly?

Heres an example of one of my calls:

+ (void)listsForUser:(NSString *)username
            response:(void (^)(NSArray *lists))completion
{
    NSString *path = [NSString stringWithFormat:@"user/list.json/%@/%@", TRAKT_API_KEY, username];
    [TNTraktAPIManager requestWithMethod:GET
                                    path:path
                              parameters:nil
                                callback:^(id response) {
                                    completion(response);
                                }];
}

Which calls the following helper method

+ (void)requestWithMethod:(HTTPMethod)method
                     path:(NSString *)path
               parameters:(NSDictionary *)params
                 callback:(void (^)(id response))completion
{
    NSString *methodString = @"POST";
    if (method == GET) {
        methodString = @"GET";
    }


    // Setup request
    NSURLRequest *request = [[TraktAPIClient sharedClient] requestWithMethod:methodString
                                                                        path:path
                                                                  parameters:params];

    // Setup operation
    AFJSONRequestOperation *operation =
    [AFJSONRequestOperation JSONRequestOperationWithRequest:request
                                                    success:^(NSURLRequest *request,
                                                              NSHTTPURLResponse *response,
                                                              id JSON) {
                                                        id jsonResults = JSON;
                                                        completion(jsonResults);

                                                    } failure:^(NSURLRequest *request,
                                                                NSHTTPURLResponse *response,
                                                                NSError *error,
                                                                id JSON) {

                                                        id jsonResults = JSON;
                                                        completion(jsonResults);
                                                        NSLog(@"%s: error: %@", __PRETTY_FUNCTION__, error);

                                                    }];
    // TODO: Queue operations
    [operation start];

}
Was it helpful?

Solution

If you set a shouldEventually expectation on the helper class and use the receive:(SEL)withArguments:(id)... form, then you can check that the argument received is what you'd expect it to be.

Two gotchas worth knowing about are setting the expectation before making the call; and using the shouldEventually form rather than should so that the test is delayed long enough for the call to be made.

OTHER TIPS

I highly recommend checking out OHHTTPStubs for unit testing your API Classes.

Unit tests should be deterministic and adding internet a potentially unpredictable API into the mix makes the testing conditions non-deterministic.

OHTTPStubs will allow you to stub the response to your outgoing HTTP Requests. Basically, it intercepts your HTTP Traffic and if the request matches criteria that you set, it gives a canned response that you declare in JSON (rather than an unpredictable result from the API). This allows you to configure different response scenarios in your test classes: ie. 404 error, partial response data, etc.. to use in your tests.

Here's an example:

I created this JSON Stub and saved as a JSON file:

{
    "devices" :     [
                   {
                     "alarm" :            {
                     "alarm_id" : 1,
                   "attack_time" : "<null>",
                   "defined_time" : "2014-04-14T04:21:36.000Z",
                   "device_id" : 7,
                   "is_protected" : 0
                   },
                   "device_type" : "iPhone",
                   "id" : 7,
                   "os_version" : "7.1"
                   }
                   ],
    "email" : "mystubemail@gmail.com",
    "facebook_id" : 5551212,
    "id" : 3,
    "name" : "Daffy Duck"
}

Whenever I network requests are made in the API Call, this JSON is returned because of this OHHTTPStub which is declared in the test class to run before all tests.

[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
            BOOL stringFound;

            if ([[request.URL description] rangeOfString:[NSString stringWithFormat:@"%@devices/register?", BASEURL]].location != NSNotFound)
            {
                stringFound = YES;
            }
            NSLog(@"%d", stringFound);

            return stringFound;

        } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) {
            // Stub it with our "RegisterDevice.json" stub file

            return [[OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"RegisterDevice.json",bundle)
                                                     statusCode:200 headers:@{@"Content-Type":@"text/json"}] requestTime:1.0 responseTime:1.0];
        }];

I'm not sure if Kiwi allows for async testing, but if not I also recommend looking into Specta and the matching framework Expecta. They allow for super easy Asynchronous unit testing, which when combined with OHHTTPStubs provides all you need to unit test API Calls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top