【问题标题】:Unit Tests for designs that use notifications使用通知的设计的单元测试
【发布时间】:2011-06-01 17:47:45
【问题描述】:

我在测试一些使用通知的逻辑时遇到了困难。我读过关于 enforcing that particular NSNotifications are sent 的文章,但这并不能真正解决我所看到的问题。

[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.");
}

我尝试在调用PerformAsyncOperation 之后休眠线程,以及一个空的while (!operationCompleted) 循环。两者都不起作用 - 休眠线程仍然使断言失败,并且 while 循环永远不会退出。我也尝试将断言移动到success:failure:,但是因为OCUnit 期望每个方法都是测试方法,所以它立即执行所有三个方法并退出(不等待NSURLRequest 的响应,这就是练习的重点!)。

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

【问题讨论】:

    标签: xcode unit-testing ios4 ocunit observer-pattern


    【解决方案1】:

    您面临的问题不是通知,而是同步的。相反,您正在触发异步操作。要使这是一个可重复的测试,您需要重新同步。

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

    在此之后,您知道操作已完成,或者测试已超时。

    【讨论】:

    • 我强烈建议使用为您提供语法糖的断言框架。例如,我使用 Specta github.com/specta/specta/tree/0.3-wip,它提供了一个名为 waitUntil(^{}) 的函数。您将代码放在块中,如果它没有在可配置的时间(默认为 10 秒)内完成,则测试失败。否则成功。
    • 是的,许多测试框架都提供了这一点。最近添加的包括 Apple 的 XCTest 和我的 OCHamcrest。
    【解决方案2】:

    为简单起见,如果可能,请使用同步网络请求。

    - (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]]);
        }];
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      • 2011-04-19
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 2013-01-02
      相关资源
      最近更新 更多