单元测试使用通知的设计

Dan*_*son 6 xcode unit-testing ocunit ios4 observer-pattern

我在测试一些使用通知的逻辑时遇到了困难.我已经阅读了有关强制执行特定信息NSNotifications的内容,但这并没有真正解决我所看到的问题.

[SomeObject PerformAsyncOperation]创建一个NSURLRequest并将自己设置为响应委托.根据响应的内容,将SomeObject成功或失败发布NSNotification到默认值NSNotificationCenter.

我的测试的问题是,在PerformAsyncOperation调用之后,测试不会等待响应被发送.相反,它继续使用断言 - 失败,因为请求/响应没有时间发送/接收/解析.

这是代码:

-(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.");
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试在调用之后休眠线程PerformAsyncOperation,以及一个空while (!operationCompleted)循环.两者都不起作用 - 休眠线程仍然无法断言,而while循环永远不会退出.我也尝试将断言移入success:和中failure:,但由于OCUnit期望每个方法都是一个测试方法,它只是立即执行所有三个方法并退出(不等待NSURLRequest响应,这是练习的全部要点! ).

任何想法或见解将不胜感激.谢谢!

Jon*_*eid 15

您遇到的问题不是通知,它是同步的.相反,它是你正在启动异步操作.要使其成为可重复的测试,您需要重新同步事物.

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];
Run Code Online (Sandbox Code Playgroud)

除此之外,您知道操作已完成或测试超时.