2013-09-30 21 views
9

i Aşağıda bu kod olarak AFNetworking ile JSON verileri almak için bir GET isteği yapıyorum için:nasıl Birim test AFNetworking isteği

 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]; 

şey ben bu verilere dayalı bir birim test oluşturmak istiyor, ama ben Testin aslında isteği yapmasını istemiyorum. Önceden tanımlanmış bir yapının yanıt olarak geri dönmesini istiyorum. Ben ünite testleri için yeni biriyim ve OCMock'dan biraz derine baktım ama bunu nasıl yöneteceğimi anlayamıyorum.

+0

[Nocilla] 'ya bakabilirsiniz (https://github.com/luisobo/Nocilla). Mevcut "NSURLConnections" içine kolayca bağlanmanızı ve davranışlarını tanımlamanızı sağlar. – mAu

cevap

12

Sorunuz hakkında yorum yapmak için birkaç şey. Öncelikle, kodunuzu test etmek zor çünkü doğrudan AFHTTPClient'i yaratıyor. Bunun bir örnek olduğu için mi bilmiyorum, ama bunun yerine enjekte etmelisiniz (aşağıdaki örneğe bakınız).

İkincisi, isteği oluşturuyorsunuz, sonra AFHTTPRequestOperation'ı oluşturuyorsunuz ve sonra bunu siz yazıyorsunuz. Bu iyi, ancak aynı AFHTTPClient yöntemi getPath: parametreleri: success: failure:.

Önerilen HTTP kuyruğu aracıyla (Nocilla) deneyimim yok, ancak NSURLProtocol'u temel aldığını görüyorum. Bazılarının bu yaklaşımı kullandığını biliyorum, ancak kendi kodlanmış yanıt nesnelerini oluşturmayı ve aşağıdaki kodda gördüğünüz gibi http istemcisiyle dalga geçmeyi tercih ediyorum.

Retriever, AFHTTPClient'i enjekte ettiğimiz yeri test etmek istediğimiz sınıftır. Kullanıcıları ve olay kimliğini doğrudan geçtiğimi unutmayın, çünkü işleri basit ve kolay bir şekilde test etmek istiyorum. Sonra başka yerde bu yönteme accout uid değerini geçerdi ve benzeri ... başlık dosyası buna benzer görünecektir:

#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 

Uygulama dosyası:

#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 

Ve Test : yorum yapmak

#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 

son şey AFNetworking 2.0 sürümü gerekliliklerini karşılar eğer kullanmayı düşünün böylece serbest olmasıdır.