how to unit testing AFNetworking request

老子叫甜甜 提交于 2019-11-29 04:12:34

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).

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:.

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

Implementation file:

#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

And the 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

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!