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)