Cómo probar una unidad de request de AFNetworking

Estoy haciendo una request GET para recuperar datos JSON con AFNetworking como este código a continuación:

  NSURL *url = [NSURL URLWithString:K_THINKERBELL_SERVER_URL]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; Account *ac = [[Account alloc]init]; NSMutableURLRequest *request = [httpClient requestWithMethod:@"GET" path:[NSString stringWithFormat:@"/user/%@/event/%@",ac.uid,eventID] parameters:nil]; AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) { NSError *error = nil; NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error]; if (error) { } [self.delegate NextMeetingFound:[[Meeting alloc]init] meetingData:JSON]; } failure:^(AFHTTPRequestOperation *operation, NSError *error){ }]; [httpClient enqueueHTTPRequestOperation:operation]; 

la cosa es que quiero crear una testing de unidad basada en estos datos, pero no quiero que la testing realmente haga la request. Quiero que una estructura pnetworkingefinida regrese como la respuesta. Soy un poco nuevo en las testings unitarias, y he pinchado un poco de OCMock pero no puedo entender cómo manejar esto.

Varias cosas para comentar sobre su pregunta. En primer lugar, su código es difícil de probar porque está creando el AFHTTPClient directamente. No sé si es porque es solo una muestra, pero debes inyectarla en su lugar (mira el ejemplo a continuación).

Segundo, está creando la request, luego la AFHTTPRequestOperation y luego la enqueue. Esto está bien, pero puede get lo mismo utilizando el método AFHTTPClient getPath: parameters: success: failure :.

No tengo experiencia con la sugerida herramienta de apantallamiento HTTP (Nocilla), pero veo que se basa en NSURLProtocol. Sé que algunas personas usan este enfoque, pero prefiero crear mis propios objects de respuesta aplastados y burlarme del cliente http como se ve en el siguiente código.

Retriever es la class que queremos probar donde inyectamos AFHTTPClient. Tenga en count que estoy pasando directamente el identificador de usuario y evento, ya que quiero mantener las cosas simples y fáciles de probar. Luego, en otro lugar, pasaría el valor de uid de acceso a este método y así sucesivamente … El file de encabezado sería similar a esto:

 #import <Foundation/Foundation.h> @class AFHTTPClient; @protocol RetrieverDelegate; @interface Retriever : NSObject - (id)initWithHTTPClient:(AFHTTPClient *)httpClient; @property (readonly, strong, nonatomic) AFHTTPClient *httpClient; @property (weak, nonatomic) id<RetrieverDelegate> delegate; - (void) retrieveEventWithUserId:(NSString *)userId eventId:(NSString *)eventId; @end @protocol RetrieverDelegate <NSObject> - (void) retriever:(Retriever *)retriever didFindEvenData:(NSDictionary *)eventData; @end 

Archivo de implementación:

 #import "Retriever.h" #import <AFNetworking/AFNetworking.h> @implementation Retriever - (id)initWithHTTPClient:(AFHTTPClient *)httpClient { NSParameterAssert(httpClient != nil); self = [super init]; if (self) { _httpClient = httpClient; } return self; } - (void)retrieveEventWithUserId:(NSString *)userId eventId:(NSString *)eventId { NSString *path = [NSString stringWithFormat:@"/user/%@/event/%@", userId, eventId]; [_httpClient getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { NSDictionary *eventData = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:NULL]; if (eventData != nil) { [self.delegate retriever:self didFindEventData:eventData]; } } failure:nil]; } @end 

Y la testing:

 #import <XCTest/XCTest.h> #import "Retriever.h" // Collaborators #import <AFNetworking/AFNetworking.h> // Test support #import <OCMock/OCMock.h> @interface RetrieverTests : XCTestCase @end @implementation RetrieverTests - (void)setUp { [super setUp]; // Put setup code here; it will be run once, before the first test case. } - (void)tearDown { // Put teardown code here; it will be run once, after the last test case. [super tearDown]; } - (void) test__retrieveEventWithUserIdEventId__when_the_request_and_the_JSON_parsing_succeed__it_calls_didFindEventData { // Creating the mocks and the retriever can be placed in the setUp method. id mockHTTPClient = [OCMockObject mockForClass:[AFHTTPClient class]]; Retriever *retriever = [[Retriever alloc] initWithHTTPClient:mockHTTPClient]; id mockDelegate = [OCMockObject mockForProtocol:@protocol(RetrieverDelegate)]; retriever.delegate = mockDelegate; [[mockHTTPClient expect] getPath:@"/user/testUserId/event/testEventId" parameters:nil success:[OCMArg checkWithBlock:^BOOL(void (^successBlock)(AFHTTPRequestOperation *, id)) { // Here we capture the success block and execute it with a stubbed response. NSString *jsonString = @"{\"some valid JSON\": \"some value\"}"; NSData *responseObject = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; [[mockDelegate expect] retriever:retriever didFindEventData:@{@"some valid JSON": @"some value"}]; successBlock(nil, responseObject); [mockDelegate verify]; return YES; }] failure:OCMOCK_ANY]; // Method to test [retriever retrieveEventWithUserId:@"testUserId" eventId:@"testEventId"]; [mockHTTPClient verify]; } @end 

Lo último que comentar es que se lanza la versión 2.0 de AFNetworking, así que considere usarla si cubre sus requisitos.