2013-09-30 19 views
9

sto facendo una richiesta GET per recuperare JSON dati con AFNetworking come questo codice qui sotto:come unità di richiesta di test AFNetworking

 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 è che voglio per creare una prova di unità in base a questi dati, ma io non voglio che il test faccia effettivamente la richiesta. Voglio una struttura predefinita restituirà come risposta. Sono un po 'nuovo al test delle unità, e ho spinto un po' di OCMock ma non riesco a capire come gestirlo.

+0

Si consiglia di dare un'occhiata a [Nocilla] (https://github.com/luisobo/Nocilla). Ti permette di agganciarti facilmente alle 'NSURLConnections 'esistenti e definire il loro comportamento. – mAu

risposta

12

Diverse cose da commentare sulla tua domanda. Prima di tutto, il codice è difficile da testare perché sta creando direttamente AFHTTPClient. Non so se è perché è solo un esempio, ma dovresti iniettarlo invece (vedi l'esempio sotto).

In secondo luogo, si sta creando la richiesta, quindi AFHTTPRequestOperation e quindi si accoda. Questo va bene ma puoi ottenere lo stesso usando il metodo AFHTTPClient getPath: parameters: success: failure :.

Non ho esperienza con quello strumento di stub HTTP suggerito (Nocilla) ma vedo che è basato su NSURLProtocol. So che alcune persone usano questo approccio, ma preferisco creare i miei oggetti risposta personali e deridere il client http come si vede nel seguente codice.

Retriever è la classe che vogliamo testare dove iniettare AFHTTPClient. Si noti che sto passando direttamente l'id utente e l'evento, dal momento che voglio mantenere le cose semplici e facili da testare. Poi in altro luogo si potrebbe passare il valore uid accout a questo metodo e così via ... Il file di intestazione dovrebbe essere simile a questo:

#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 

file di implementazione:

#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 

e il test :

#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 

l'ultima cosa di commentare è che la versione AFNetworking 2.0 viene rilasciato in modo considerare l'utilizzo che se copre le vostre esigenze.