Swift-testing: what's the recommend approach to test throwing function?

You can use #expect(throws:), which comes in a few varieties:

How can I test that any error was thrown?

#expect(throws: (any Error).self) {
  try foo()
}

How can I test that an error of a specific type was thrown?

#expect(throws: FooError.self) {
  try foo()
}

How can I test that an exact error was thrown?

#expect(throws: FooError.insufficientWidgets) {
  try foo()
}

Note that this case is available only if your error type conforms to Equatable.

How can I test that an error was thrown with more complex requirements?

#expect {
  try foo()
} throws: { error in
  guard let error = error as? FooError else {
    return false
  }
  return error.widgetCount > 123 && error.isFunny
}

How can I test that no error was thrown?

Either call the throwing function directly—and if an error is thrown, allow the test to fail—or, if you want to emphasize the semantics of the function not throwing, use Never with #expect(throws:):

#expect(throws: Never.self) {
  try foo()
}
9 Likes