Reputation: 4822
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];
}
Upvotes: 4
Views: 2964
Reputation: 606
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" : "[email protected]",
"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.
Upvotes: 4
Reputation: 8522
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.
Upvotes: 5