Модульные тесты для проектов, которые используют уведомления - PullRequest
5 голосов
/ 01 июня 2011

У меня проблемы с проверкой логики, использующей уведомления.Я читал о принудительном выполнении, что конкретные NSNotifications отправляются , но это не решает проблему, с которой я сталкиваюсь.

[SomeObject PerformAsyncOperation] создает NSURLRequest и устанавливаетсам как ответчик делегат.В зависимости от содержания ответа SomeObject отправляет сообщение об успехе или неудаче NSNotification по умолчанию NSNotificationCenter.

Проблема с моим тестом заключается в том, что после вызова PerformAsyncOperation тест не выполняетсяt ждать ответа, который будет отправлен.Вместо этого он продолжается с утверждением - что не удается, поскольку запрос / ответ не успел быть отправлен / получен / проанализирован.

Вот код:

-(void)testMethod {
    SomeObject *x = [[SomeObject alloc] init];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                        selector:@selector(success:)
                                            name:SomeObjectSuccess
                                          object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                        selector:@selector(failure:)
                                            name:SomeObjectFailure
                                          object:nil];

    operationCompleted = false; // declared in .h

    [x PerformAsyncOperation:@"parameter"];

    STAssertTrue(operationCompleted , @"Operation has completed.");

    [[NSNotificationCenter defaultCenter] removeObserver:self name:SomeObjectSuccess object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:SomeObjectFailure object:nil];

    [x release];
}

-(void) failure:(NSNotification *) notification {
   operationCompleted = true;
   NSLog(@"Received failure message.");
}

-(void) success:(NSNotification *) notification {
   operationCompleted = true;
   NSLog(@"Received success message.");
}

Я пробовал спать нить после вызова PerformAsyncOperation, а также пустой цикл while (!operationCompleted).Ни то, ни другое не работает - спящий поток все равно не может выполнить assert, и цикл while никогда не завершается.Я также попытался переместить утверждения в success: и failure:, но поскольку OCUnit ожидает, что каждый метод будет тестовым, он просто сразу выполняет все три метода и завершает работу (не ожидая ответа NSURLRequest,в этом весь смысл упражнения!).

Буду очень признателен за любые идеи или идеи.Спасибо!

Ответы [ 2 ]

15 голосов
/ 03 июня 2011

Проблема, с которой вы сталкиваетесь, заключается не в синхронных уведомлениях. Скорее, вы запускаете асинхронную операцию. Чтобы сделать этот тест повторяемым, вам необходимо выполнить повторную синхронизацию.

NSTimeInterval timeout = 2.0;   // Number of seconds before giving up
NSTimeInterval idle = 0.01;     // Number of seconds to pause within loop
BOOL timedOut = NO;

NSDate *timeoutDate = [[NSDate alloc] initWithTimeIntervalSinceNow:timeout];
while (!timedOut && !operationCompleted)
{
    NSDate *tick = [[NSDate alloc] initWithTimeIntervalSinceNow:idle];
    [[NSRunLoop currentRunLoop] runUntilDate:tick];
    timedOut = ([tick compare:timeoutDate] == NSOrderedDescending);
    [tick release];
}
[timeoutDate release];

За пределами этой точки вы знаете, что либо операция завершена, либо тест завершен.

0 голосов
/ 11 июня 2015

По причинам простоты и, если возможно, используйте синхронные сетевые запросы.

- (void)testExample
{
    [self measureBlock:^{

        NSURLRequest *request = [[NSURLRequest alloc] initWith...];

        NSHTTPURLResponse *response = nil;
        NSData *data = [NSURLConnection sendSynchronousRequest:request
                                         returningResponse:&response
                                                     error:nil];

        XCTAssertEqual(response.statusCode,200);

        // process the data from response ... call the delegate methods or whatever

        NSObject *object = [NSJSONSerialization JSONObjectWithData:data
                                                       options:NSJSONReadingMutableContainers
                                                         error:nil];
        XCTAssertTrue([object isKindOfClass:[NSArray class]]);
    }];
}
...