How to test a class that processes an HTTP request and parses response data in Obj-C?

I have a class that needs to make an HTTP request to the server to get some information. For instance:

- (NSUInteger)newsCount { NSHTTPURLResponse *response; NSError *error; NSURLRequest *request = ISKBuildRequestWithURL(ISKDesktopURL, ISKGet, cookie, nil, nil); NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; if (!data) { NSLog(@"The user's(%@) news count could not be obtained:%@", username, [error description]); return 0; } NSString *regExp = @"Usted tiene ([0-9]*) noticias? no leΓ­das?"; NSString *stringData = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; NSArray *match = [stringData captureComponentsMatchedByRegex:regExp]; [stringData release]; if ([match count] < 2) return 0; return [[match objectAtIndex:1] intValue]; } 

The fact is that I am doing unit testing (using OCUnit), but the problem is that I need to simulate / fake what NSURLConnection answers to test different scenarios, and because I can not relay to the server to check my infrastructure .

So the question is: What are the best ways to do this?

+4
source share
1 answer

It's always hard to test methods that call class methods, such as NSURLConnection sendSynchronousRequest

Here are a few options:

a) Use Matt Gallagher invokeSupersequent macro to intercept the call. Your unit test will contain this code:

 @implementation NSURLConneciton (UnitTests) + (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error { if (someFlagYourTestUsesToInterceptTheCall) { // return test NSData instance } return invokeSupersequent(request, &response, &error); } @end 

Then you set someFlagYourTestUsesToInterceptTheCall to make it intercept the call and return the test data.

b) Another alternative is to port this call to your own method in the test class:

 -(NSData *)retrieveNewsCount:(NSURLRequest *)request { NSHTTPURLResponse *response; NSError *error; return [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; } 

Then intercept this call in a test case using OCMock:

 -(void)testNewsCount { // instantiate your class id myObject = ...; id mock = [OCMockObject partialMockForObject:myObject]; [[[mock stub] andCall:@selector(mockNewsCount:) onObject:self] retrieveNewsCount:[OCMArg any]]; NSUInteger count = [myObject newsCount]; // validate response ... } // in the same test class: -(NSData *)mockNewsCount:(NSURLRequest *)request { // return your mock data return mockData; } 

In this case, OCMock stub:andCall:onObject:someMethod intercepts this call only to your object in order to insert some test data during testing.

+4
source

Source: https://habr.com/ru/post/1304708/


All Articles