如何unit testingAFNetworking请求

我正在做一个GET请求检索JSON数据与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]; 

事情是我想创build一个基于这个数据的unit testing,但我不希望testing实际上会提出请求。 我想要一个预定义的结构将返回作为响应。 我对unit testing是一种新鲜的东西,并且使用了一点OCMock但是不知道如何pipe理它。

有几件事要评论你的问题。 首先,你的代码很难testing,因为它直接创buildAFHTTPClient。 我不知道是不是因为这只是一个样本,而应该注入它(请参阅下面的示例)。

其次,你正在创build请求,然后AFHTTPRequestOperation,然后你排队。 这很好,但你可以使用AFHTTPClient方法getPath:parameters:success:failure :.

我没有经验,build议HTTP stubbing工具(Nocilla),但我看到它是基于NSURLProtocol。 我知道有些人使用这种方法,但我更喜欢创build自己的存根响应对象,并嘲笑http客户端,就像你在下面的代码中看到的一样。

Retriever是我们要testing的地方,我们注入了AFHTTPClient。 请注意,我直接传递用户和事件ID,因为我想保持简单和容易testing的事情。 然后在其他地方,你可以将accout的uid值传递给这个方法,等等…头文件看起来类似于:

 #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 

实施文件:

 #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 

和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 

最后要说的是,AFNetworking 2.0版本已经发布了,所以如果它满足你的要求的话,请考虑使用它。