如何对AFNetworking请求进行单元测试 [英] how to unit testing AFNetworking request

查看:102
本文介绍了如何对AFNetworking请求进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作 GET 请求,以 AFNetworking JSON 数据c $ c>如下面的代码:

i am making a GET request to retrieve JSON data with AFNetworking as this code below :

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

我想根据这些数据创建一个单元测试,但我不想要那个测试实际上会提出请求。我希望预定义的结构将作为响应返回。我是一个新的单元测试,并且点了一点 OCMock 但是无法弄清楚如何管理它。

the thing is i want to create a unit test based on this data, but i dont want that the test will actually make the request. i want a predefined structure will return as the response. i am kind'a new to unit testing, and poked a little of OCMock but cant figure out how to manage this.

推荐答案

对您的问题发表评论的几件事情。
首先,您的代码很难测试,因为它直接创建了AFHTTPClient。我不知道是不是因为它只是一个样本,但你应该注入它(参见下面的示例)。

Several things to comment about your question. First of all, your code is hard to test because it is creating the AFHTTPClient directly. I don't know if it's because it's just a sample, but you should inject it instead (see the sample below).

其次,您正在创建请求,然后是AFHTTPRequestOperation,然后您将其排队。这很好,但你可以使用AFHTTPClient方法得到相同的getPath:参数:成功:失败:。

Second, you are creating the request, then the AFHTTPRequestOperation and then you enqueue it. This is fine but you can get the same using the AFHTTPClient method getPath:parameters:success:failure:.

我没有使用建议的HTTP存根工具(Nocilla)的经验)但我发现它基于NSURLProtocol。我知道有些人使用这种方法,但我更喜欢创建自己的存根响应对象并模拟http客户端,如下面的代码所示。

I do not have experience with that suggested HTTP stubbing tool (Nocilla) but I see it is based on NSURLProtocol. I know some people use this approach but I prefer to create my own stubbed response objects and mock the http client like you see in the following code.

Retriever是我们的类想测试我们注入AFHTTPClient的位置。
请注意,我直接传递用户和事件ID,因为我希望保持简单易用的测试。然后在其他地方你将accout uid值传递给这个方法等等...
头文件看起来类似于:

Retriever is the class we want to test where we inject the AFHTTPClient. Note that I am passing directly the user and event id, since I want to keep things simple and easy to test. Then in other place you would pass the accout uid value to this method and so on... The header file would look similar to this:

#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

测试:

#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版本已经发布,所以如果它满足您的要求,请考虑使用它。

The last thing to comment is that the AFNetworking 2.0 version is released so consider using it if it covers your requirements.

这篇关于如何对AFNetworking请求进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆