开发者

Unit Tests for designs that use notifications

开发者 https://www.devze.com 2023-03-10 05:24 出处:网络
I\'m having difficulty testing some logic that uses notifications. I\'ve read about enforcing that particular NSNotifications are sent, but that doesn\'t really address the problem I\'m seeing.

I'm having difficulty testing some logic that uses notifications. I've read about enforcing that particular NSNotifications are sent, but that doesn't really address the problem I'm seeing.

[SomeObject PerformAsyncOperation] creates an NSURLRequest and sets itself as the response delegate. Depending on the content of the response, SomeObject posts a success or failure NSNotification to the default NSNotificationCenter.

The problem with my test is that after PerformAsyncOperation is called, the test doesn't wait for the response to be sent. Instead, it continues on with the assert - which fails, because the request/response hasn't had time to be sent/received/parsed.

Here is the code:

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

I've tried sleeping the thread after the call to PerformAsyncOperation, as well as an empty while (!operationCompleted) loop. Neither works 开发者_运维问答- sleeping the thread still fails the assert, and the while loop never exits. I've also tried moving the asserts into success: and failure:, but because OCUnit expects each method to be a test method, it just executes all three methods immediately and quits (without waiting for the NSURLRequest's response, which is the whole point of the exercise!).

Any ideas or insight would be greatly appreciated. Thanks!


The problem you face is not notifications, which are synchronous. Rather, it is that you are firing off an asynchronous operation. To make this a repeatable test, you need to resynchronize things.

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

Beyond this point, you know that either the operation completed, or the test timed out.


For simplicity reasons, and if possible, use the synchronous network requests.

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号