XCTestExpectation: how to avoid calling the fulfill method after the wait context has ended?

空扰寡人 提交于 2019-12-02 18:10:57

Yes, there is a much simpler way to avoid this API violation issue: just declare your expectation variable as __weak. Although not clearly documented, the expectation will be released when the timeout expires. So if the task takes longer than the timeout, the expectation variable will be nil when the task completion handler is called. Thus the fulfill method will be called on nil, doing nothing.

- (void) test1TaskLongerThanTimeout
{
    __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Test 1: task longer than timeout"];
    [self startAsynchronousTaskWithDuration:4 completionHandler:^(id result, NSError *error) {
        XCTAssertNotNil(result);
        XCTAssertNil(error);
        [expectation fulfill];
    }];
    [self waitForExpectationsWithTimeout:2 handler:nil];
}

I came across the same problem but in my case I needed the Swift version of the answer above.

I'm working on an OpenStack Swift Drive for OSX. When a folder is deleted locally with Finder, the deletion eventually propagates to the Server, I needed a test that waits for the server to be updated.

To avoid the API violation crash, I've changed my expectations to be "weak var" and changed the call to fulfill it to "zeroFoldersExpectation?.fulfill()" with the extra '?' as the expectation is now optional and could become nil in which case the fulfill call is ignored. This fixed the crashes.

func testDeleteFolder()
{
    Finder.deleteFolder()

    weak var zeroFoldersExpectation=expectationWithDescription("server has zero folders")
    Server.waitUntilNServerFolders(0, withPrefix: "JC/TestSwiftDrive/", completionHandler: {zeroFoldersExpectation?.fulfill()})
    waitForExpectationsWithTimeout(10, handler: {error in})

}
Piotr

Instead of creating expectation as weak variable (as suggested in this answer) I think you could also set is as block variable and nil it in completion handler of waitForExpectationsWithTimeout:

- (void) test1TaskLongerThanTimeout
{
    __block XCTestExpectation *expectation = [self expectationWithDescription:@"Test 1: task longer than timeout"];
    [self startAsynchronousTaskWithDuration:4 completionHandler:^(id result, NSError *error) {
        XCTAssertNotNil(result);
        XCTAssertNil(error);
        [expectation fulfill];
    }];
    [self waitForExpectationsWithTimeout:2 handler:^(NSError *error) {
        expectation = nil;
    }];
}

This way you are sure that ARC won't dealloc expectation too fast.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!