Модульные Тесты AFNetworking


Я пытаюсь выполнить модульный тест, используя приведенный ниже код. Однако тест просто зависает на участке ожидания. Ниже приведен мой тестовый код. Я новичок в iOS и AFNetworking. Любая помощь будет оценена по достоинству.

Вещи, Которые Я Знаю.: Вызывается метод в USAPIConnection. На TestController не вызывается метод success или failure. Запрос к API rails работает. (Я знаю, что он возвращает код 200 OK).

Вещи, которых я не знаю.: Является ли AFHTTPRequestOperationManager действительно отправляете запрос? Почему нет ни одного успешного метода отказа, который был бы послан? Должен ли этот модульный тест быть достаточным для тестирования?

XCTest Код

#import <XCTest/XCTest.h>
#import "USAPIConnection.h"
#import "Controller.h"

@interface TestController : NSObject <Controller>

@property bool done;

@end

@implementation TestController

-(void)asynchronousSuccessfulWithObject:(id)object type:(int)type{
    NSLog(@"Object: %@", object);
    XCTAssertNotNil(object,"@Should have returned JSON object: %s",__PRETTY_FUNCTION__);
    _done = true;

}
-(void)asynchronousUnsuccessfulWithError:(NSError *)error type:(int)type{
    XCTFail(@"Unsuccessful async call with error%s: %s",error,__PRETTY_FUNCTION__);
    _done = true;
}

@end

@interface USAPIConnectionTests : XCTestCase

@end

@implementation USAPIConnectionTests

- (void)setUp
{
    [super setUp];
    NSLog(@"Beginning Test: %s",__PRETTY_FUNCTION__);
}

- (void)tearDown
{
    NSLog(@"Ending Test: %s",__PRETTY_FUNCTION__);
    [super tearDown];
}

- (void)testGetTeamById
{
    TestController* testController = [[TestController alloc] init];
    testController.done = false;
    [USAPIConnection getTeamById:1 controller:testController];
    int count = 0;
    while(!testController.done && count < 10){
        //Waiting
        [NSThread sleepForTimeInterval:3.0];
        count = count + 1;
    }
    if(count == 10){
        XCTFail(@"Timed out: %s",__PRETTY_FUNCTION__);
    }
}

@end

Метод, вызываемый в USAPIConnection

+(void)getTeamById:(int)identity controller:(id<Controller>)controller{
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    AFJSONResponseSerializer* serializer = [AFJSONResponseSerializer serializer];
    serializer.acceptableContentTypes = [NSSet setWithObject:@"application/json"];
    manager.responseSerializer = serializer;
    [manager POST:[NSString stringWithFormat:@"http://%@/team/%D",baseURL,identity] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [controller asynchronousSuccessfulWithObject:responseObject type:TYPETEAMSBYNAME];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [controller asynchronousUnsuccessfulWithError:error type:TYPETEAMSBYNAME];
    }];
}

Попытки

Попытка изменить метод испытания на следующий. Однако ни один NSLog в контроллере тестирования не работал.

- (void)testGetTeamById
{
    TestController* testController = [[TestController alloc] init];
    testController.done = false;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{[USAPIConnection getTeamById:1 controller:testController];});
    //dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{NSLog(@"HELLO FROM ASYNC QUEUE");});
}
2 3

2 ответа:

XCTest в Xcode 6 (еще не выпущенном на момент написания статьи) поддерживает тестирование асинхронных методов.

Вот небольшой фрагмент в Swift, который показывает, как это может выглядеть:

Предположим, что у вас есть асинхронный метод с функцией завершения в качестве параметра:

func doSomethingAsync(completion:(result: Int?, error: Int?) -> ())

Теперь вы хотите проверить, успешно ли выполняется эта асинхронная функция, или вы хотите проверить некоторый код, который вы определяете в продолжении (обработчике завершения):

func testAsyncFunction() {
    let expect = self.expectationWithDescription("completion handler called")
    doSomethingAsync { (result, error) -> () in
        if let value = result? {
            println("Result: \(value)")
        }
        else {
            println("Error: \(error!)")
        }
        expect.fulfill()
    }
    waitForExpectationsWithTimeout(1000, handler: nil)
}

Вы можете читать подробнее о новых методах XCTest self.expectationWithDescription: fulfill и waitForExpectationsWithTimeout: в заголовках XCTest.

Я сейчас занимаюсь модульным тестированием с помощью этой новой асинхронной тестовой установки. Просто отсутствует некоторая функциональность, например, наличие метода reject наряду с fulfill с необязательным строковым параметром для ведения журнала. ИМО, это выглядит довольно привлекательным, и это работает отлично до сих пор. Итак, я действительно призываю вас заглянуть в бета-версию Xcode;

Тем временем, вы можете найти библиотеку "promise", применимую к реализовать тестирование асинхронных методов. Я предложил использовать библиотеку RXPromise (я автор) для модульного тестирования несколько раз на этом форуме. ;)

Для выполнения асинхронного вызова в UnitTest необходимо что-то вроде флага. Это так много обсуждается здесь:

Как проводить модульное тестирование асинхронных API?