Home > database >  Unexpected behavior of XCTWaiter.wait
Unexpected behavior of XCTWaiter.wait

Time:07-13

For testing purposes, I have the following test function:

func test_wait() {
    var string: String?
    DispatchQueue.main.async {
        string = "set"
        print("string set")
    }
    let notNilPredicate = NSPredicate(format: "self != nil")
    let notNilExpectation = expectation(for: notNilPredicate, evaluatedWith: string)
    print("start waiting")
    let waitResult = XCTWaiter.wait(for: [notNilExpectation], timeout: 5)
    XCTAssert(waitResult == .completed, "wait for notNilExpectation failed with result \(waitResult)")
}  

This test fails.
The wait result is .timedOut, and the log is

start waiting
string set
… : XCTAssertTrue failed - wait for notNilExpectation failed with result XCTWaiterResult(rawValue: 2)
Interrupting test  

I do not understand why the wait fails although var string is set.
However, the test succeeds when I out comment DispatchQueue.main.async, i.e. when I execute its block synchronously. The log is then

string set
start waiting
Test Case '-[ShopEasyTests.CoreDataCloudKitContainerTest test_wait]' passed (1.087 seconds).  

To my understanding, the async version of the test function should also work.
What is wrong?

CodePudding user response:

It's the predicate (and the semantics of capture). You think you are handing a reference to string into your predicate evaluation, but you aren't; you are just passing nil, and nil is not going to magically be not-nil any time soon. To confuse yourself less, rewrite as

let notNilPredicate = NSPredicate {_,_ in string != nil }
let notNilExpectation = expectation(for: notNilPredicate, evaluatedWith: nil)
  • Related