How do you write a unit test that checks whether an async function doesn't timeout?
I'm trying with regular XCTestExpectation
, but because await
suspends everything, it can't wait for the expectation.
In the code below, I'm checking that loader.perform()
doesn't take more than 1 second to execute.
func testLoaderSuccess() async throws {
let expectation = XCTestExpectation(description: "doesn't timeout")
let result = try await loader.perform()
XCTAssert(result.value == 42)
wait(for: [expectation], timeout: 1) // execution never gets here
expectation.fulfill()
}
It might be prudent to cancel the task if it times out:
func testA() async throws {
let expectation = XCTestExpectation(description: "timeout")
let task = Task {
let result = try await loader.perform()
XCTAssertEqual(result, 42)
expectation.fulfill()
}
await fulfillment(of: [expectation], timeout: 1)
task.cancel()
}
If you do not, perform
may continue to run even after testA
finishes in the failure scenario.
The other approach would be to use a task group:
func testB() async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
let result = try await self.loader.perform()
XCTAssertEqual(result, 42)
}
group.addTask {
try await Task.sleep(for: .seconds(1))
XCTFail("Timed out")
}
let _ = try await group.next() // wait for the first one
group.cancelAll() // cancel the other one
}
}