简体   繁体   中英

How do I unit test openWithCompletionHandler

I have a unit test module derived from SenTestCase . I would like to have a unit test method that would load a UIDocument derived document I saved on the application sandbox previously. Note this test is about loading the document locally (iCloud is not configured). I know openWithCompletionHandler runs asynchronously so I understand this would never work as soon as the test function runs off the stack. Below code is given to indicate my intention (of course it doesn't work):

-(void)testLoadingDocument{
    ...
    MyDocument *document = [[MyDocument alloc] initWithFileURL:destUrl];
    STAssertNotNil(document, @"Document is nil");

    NSLog(@"LOAD: %@", document.fileURL);
    [document openWithCompletionHandler:^(BOOL success) {
        NSLog(@"openWithCompletionHandler success = %@", success);
        if (success) {
            // document.packet will be filled by loadFromContents
            STAssertNotNil(document.packet, @"document.packet is nil.");
        }
    }];
}

My question is really is there any way to test openWithCompletionHandler from within unit testing framework? I don't mind if I have to run the entire document loading operation synchronously within a block of code. Since this is a test code I thought this would be acceptable unlike code that has to run asynchronously on the device.

Many thanks in advance.

This problem took me a while to figure out. I love unit testing, but when using SenTestCase your tests do not run in the same environment your regular code would. Most importantly, you lack a main loop that has a run loop in it, making anything with async call backs prone to doing nothing.

So what's the solution? Provide a run loop ourselves and have it run until the block gets called. We use a __block variable that we set in the completion block to see when we can stop running the run loop.

-(void)testOfAsyncCallingMethod{

    __block bool wasCalled = NO;

    [testingObject methodThatRunsACompletionBlock:^{
        wasCalled = YES;
    }];

    NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:10];
    while (wasCalled == NO && [loopUntil timeIntervalSinceNow] > 0) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:loopUntil];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM