Макет NSHTTPURLRequest и NSHTTPURLResponse в модульном тесте iOS

Я разрабатываю фреймворк в iOS, который делает HTTP-вызовы на сервер. Я хотел написать модульный тест для тестирования API. Я хотел издеваться над вызовами сервера, фактически не выполняя вызов сервера. делает издевательские вызовы сервера. Как нам установить ожидания и вернуть созданный вручную ответ URL-адреса. Я использую структуру XCTest для модульного тестирования и OCMock для имитации объектов.


person Karthik207    schedule 18.12.2013    source источник
comment
Без фактического вызова сервера, как вы узнаете, отвечает ли ваш сервер так, как вы хотите?   -  person jailani    schedule 18.12.2013
comment
@jai: наша цель - в основном протестировать сервер framework.not.   -  person Karthik207    schedule 18.12.2013
comment
Кто-нибудь, пожалуйста, помогите с примером модульного теста для создания имитируемых вызовов сервера!.   -  person Karthik207    schedule 18.12.2013
comment
Как вы выполняете вызовы своего сервера (т.е. какие методы вы используете?)   -  person Ben Flynn    schedule 18.12.2013
comment
@BenFlynn: Использование NSURLConnection ...   -  person Karthik207    schedule 29.12.2013
comment
@ Karthik207 Это класс, который вы используете - какие методы? Помогает ли мой ответ ниже?   -  person Ben Flynn    schedule 30.12.2013
comment
@BenFlynn: что означает handler = [invocation getArgumentAtIndexAsObject:4]; делать?? я не понимаю часть вызова.   -  person Karthik207    schedule 30.12.2013
comment
@ Karthik207 Я попытался уточнить это в редактировании ответа.   -  person Ben Flynn    schedule 31.12.2013


Ответы (2)


Вот как можно имитировать sendAsynchronousRequest:

NSDictionary *serverResponse = @{ @"response" : [[NSHTTPURLResponse alloc] initWithURL:nil statusCode:200 HTTPVersion:nil headerFields:@{}],
                                  @"data" : [@"SOMEDATA" dataUsingEncoding:NSUTF8StringEncoding]
                                  };

id connectionMock = [OCMockObject mockForClass:NSURLConnection.class];
[[[connectionMock expect] andDo:^(NSInvocation *invocation) {
    void (^handler)(NSURLResponse*, NSData*, NSError*);
    handler = [invocation getArgumentAtIndexAsObject:4];
    handler(serverResponse[@"response"], serverResponse[@"data"], serverResponse[@"error"]);
}] sendAsynchronousRequest:OCMOCK_ANY queue:OCMOCK_ANY completionHandler:OCMOCK_ANY];

ИЗМЕНИТЬ

Чтобы внести ясность, вот что происходит. В этом примере наш реальный код вызывает [NSURLConnection sendAsynchronousRequest: queue: completionHandler:]. В этот метод передаются три аргумента плюс дополнительные _cmd и self, которые передаются всем вызовам методов Objective-C. Таким образом, когда мы проверяем наш NSInvocation, аргумент с индексом 4 является нашим обработчиком завершения. Поскольку мы моделируем ответ сервера, мы хотим вызвать этот обработчик с поддельными данными, которые представляют тестируемый нами случай.

Сигнатура для вызова метода getArgumentAtIndexAsObject находится в заголовочном файле, включенном в OCMock, но по умолчанию не включена в платформу. Кажется, это называется NSInvocation+OCMAdditions.h. Это упрощает получение аргументов вызова, возвращая id.

person Ben Flynn    schedule 18.12.2013

Используйте OHTTPStubs, https://github.com/AliSoftware/OHHTTPStubs.

Вот практический пример имитации ответа на конкретный запрос GET и возврата данных JSON.

[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) {
    return [request.URL.path isEqualToString:@"/api/widget"];
} withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) {
    id JSON = @{ @"id": @"1234", @"name" : @"gadget" };
    NSData *data = [NSJSONSerialization dataWithJSONObject:JSON options:0 error:nil];
    return [OHHTTPStubsResponse responseWithData:data statusCode:200 headers:@{ @"Content-Type": @"application/json" }];
}];
person dB.    schedule 16.01.2014
comment
Просто чтобы сэкономить ваше время, это работает, если вы не используете фоновую конфигурацию. Из документов: OHHTTPStubs не могут работать в фоновых сеансах (сеансы, созданные с помощью [NSURLSessionConfiguration backgroundSessionConfiguration]), поскольку фоновые сеансы не позволяют использовать пользовательские NSURLProtocols и обрабатываются самой операционной системой iOS. - person Luca Torella; 21.10.2015