ios unit-testing afnetworking ocmock

ios - cómo probar la unidad Solicitud de AFNetworking



unit-testing ocmock (1)

Estoy haciendo una solicitud 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];

Lo que quiero es crear una prueba unitaria basada en estos datos, pero no quiero que la prueba realmente haga la solicitud. Quiero que una estructura predefinida regrese como respuesta. Soy amable con las pruebas unitarias y OCMock un poco de OCMock pero no puedo entender cómo manejar esto.


Varias cosas para comentar sobre su pregunta. Antes que nada, su código es difícil de probar porque está creando el AFHTTPClient directamente. No sé si es porque es solo una muestra, pero debe inyectarse en su lugar (vea la muestra a continuación).

En segundo lugar, está creando la solicitud, luego AFHTTPRequestOperation y luego la pone en cola. Esto está bien, pero puede obtener lo mismo utilizando el método AFHTTPClient getPath: parameters: success: failure :.

No tengo experiencia con esa herramienta de copia HTTP sugerida (Nocilla) pero veo que está basada en NSURLProtocol. Sé que algunas personas usan este enfoque, pero yo prefiero crear mis propios objetos de respuesta troquelados y burlarme del cliente http como lo ve en el siguiente código.

Retriever es la clase que queremos probar donde inyectamos el AFHTTPClient. Tenga en cuenta que paso directamente el usuario y la identificación del evento, ya que quiero que todo sea simple y fácil de probar. Luego, en otro lugar, pasaría el valor de la cuenta a este método y así sucesivamente ... El archivo de encabezado sería similar a este:

#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 prueba:

#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 debe comentar es que la versión 2.0 de AFNetworking se ha publicado, así que considere usarla si cubre sus requisitos.