Test an async throws function and assert it threw the right error
UserLoader.load(id:) is an async throws function that must throw LoaderError.notFound when the id is not positive. Write a unit test that awaits the call and asserts it threw that specific error — not merely that some error was thrown.
Requirements:
- Use
async/awaitin the test; do not block with a semaphore. - Assert the concrete error case, so a wrong error or an unexpected success still fails.
enum LoaderError: Error, Equatable { case notFound, network }
struct UserLoader {
func load(id: Int) async throws -> String {
guard id > 0 else { throw LoaderError.notFound }
return "user-\(id)"
}
}
func testLoadThrowsNotFound() async {
// your code here
}
Write the implementation.
Await the call in an async test and assert the concrete error case, not just that some error threw. Use await #expect(throws: LoaderError.notFound) { ... }, or an XCTest do/catch that fails on success and asserts .notFound.
- ✗Asserting only that some error was thrown, not which concrete case
- ✗Blocking with a semaphore instead of writing an async test
- ✗Forgetting to fail the test when the call unexpectedly returns a value
- →How does
#expect(throws:)compare the thrown error to the expected case? - →Why must the test fail if the call returns instead of throwing?
The concrete-case assertion is the whole point — a bare try await only proves something threw.
// Swift Testing — the concise form
@Test func loadThrowsNotFound() async {
let loader = UserLoader()
await #expect(throws: LoaderError.notFound) {
try await loader.load(id: 0)
}
}
// XCTest — explicit do/catch
func testLoadThrowsNotFound() async {
let loader = UserLoader()
do {
_ = try await loader.load(id: 0)
XCTFail("expected notFound, but the call returned")
} catch {
XCTAssertEqual(error as? LoaderError, .notFound)
}
}
#expect(throws: LoaderError.notFound) fails when the closure throws a different case or does not throw at all. In the XCTest form, XCTFail on the success path guards against a silent return, and XCTAssertEqual against .notFound (thanks to Equatable) rejects a wrong error case.