Reputation: 1335
When running an XCTest of an asynchronous operation, calling XCTFail()
does not immediately fail the test, which was my expectation. Instead, whatever timeout period is remaining from the call to wait
is first exhausted, which unnecessarily extends the test time and also creates a confusing failure message implying the test failed due to timeout, when in fact it explicitly failed.
func testFoo() {
let x = expectation(description: "foo")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
XCTFail("bar")
}
wait(for: [x], timeout: 5)
}
In the above example, although the the failure occurs after roughly 2 seconds, the test does not complete until the timeout period of 5 seconds has elapsed. When I first noticed this behavior I thought I was doing something wrong, but this seems to just be the way it works, at least with the current version of Xcode (9.2).
Since I didn't find any mention of this via google or stackoverflow searches, I'm sharing a workaround I found.
Upvotes: 2
Views: 4752
Reputation: 1335
I discovered that the XCTestExpectation can still be fulfilled after calling XCTFail()
, which does not count as a pass and immediately expires the wait
. So, applying this to my initial example:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
XCTFail("bar")
x.fulfill()
}
This may be what Apple expects but it wasn't intuitive to me and I couldn't find it documented anywhere. So hopefully this saves someone else the time that I spent confused.
Upvotes: 9