【发布时间】:2015-09-30 07:30:54
【问题描述】:
如何测试 Swift 2.0 中的函数是否抛出异常?如何断言抛出了正确的ErrorType?
【问题讨论】:
标签: xcode swift unit-testing
如何测试 Swift 2.0 中的函数是否抛出异常?如何断言抛出了正确的ErrorType?
【问题讨论】:
标签: xcode swift unit-testing
编辑:更新了Swift 4.1 的代码(对Swift 5.2 仍然有效)
这是使用XCTAssertThrowsError的Fyodor Volchyok's answer的最新Swift版本:
enum MyError: Error {
case someExpectedError
case someUnexpectedError
}
func functionThatThrows() throws {
throw MyError.someExpectedError
}
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
XCTAssertEqual(error as! MyError, MyError.someExpectedError)
}
}
如果您的Error 枚举具有关联值,您可以让您的Error 枚举符合Equatable,或使用if case 语句:
enum MyError: Error, Equatable {
case someExpectedError
case someUnexpectedError
case associatedValueError(value: Int)
}
func functionThatThrows() throws {
throw MyError.associatedValueError(value: 10)
}
// Equatable pattern: simplest solution if you have a simple associated value that can be tested inside 1 XCTAssertEqual
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
XCTAssertEqual(error as! MyError, MyError.associatedValueError(value: 10))
}
}
// if case pattern: useful if you have one or more associated values more or less complex (struct, classes...)
func testFunctionThatThrows() {
XCTAssertThrowsError(try functionThatThrows()) { error in
guard case MyError.associatedValueError(let value) = error else {
return XCTFail()
}
XCTAssertEqual(value, 10)
// if you have several values or if they require more complex tests, you can do it here
}
}
【讨论】:
至少在 Xcode 7.3(可能更早)中,您可以使用内置的XCTAssertThrowsError():
XCTAssertThrowsError(try methodThatThrows())
如果在测试过程中没有抛出任何东西,您会看到如下内容:
如果你想检查抛出的错误是否是某种具体类型,你可以使用XCTAssertThrowsError()的errorHandler参数:
enum Error: ErrorType {
case SomeExpectedError
case SomeUnexpectedError
}
func functionThatThrows() throws {
throw Error.SomeExpectedError
}
XCTAssertThrowsError(try functionThatThrows(), "some message") { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
【讨论】:
给定以下函数和声明:
enum SomeError: ErrorType {
case FifthError
case FirstError
}
func throwingFunction(x: Int) throws {
switch x {
case 1:
throw SomeError.FirstError
case 5:
throw SomeError.FifthError
default:
return
}
}
如果给函数赋予 5,则该函数将抛出 FifthError,如果给定 1,则抛出 FirstError。
为了测试,一个函数成功运行单元测试可能如下所示:
func testNotError() {
guard let _ = try? throwingFunction(2) else {
XCTFail("Error thrown")
return
}
}
let _ 也可以替换为任何其他名称,因此您可以进一步测试输出。
要断言函数抛出,无论ErrorType 是什么,单元测试可能如下所示:
func testError() {
if let _ = try? throwingFunction(5) {
XCTFail("No error thrown")
return
}
}
如果您想测试特定的ErrorType,可以使用do-catch-statement 完成。与其他语言相比,这不是最好的方法。
你必须确保你...
return 在catch 中为正确的ErrorType
XCTFail() 和 return 用于所有其他 catch
XCTFail() 如果没有 catch 被执行鉴于此要求,测试用例可能如下所示:
func testFifthError() {
do {
try throwingFunction(5)
} catch SomeError.FifthError {
return
} catch {
XCTFail("Wrong error thrown")
return
}
XCTFail("No error thrown")
}
【讨论】:
Swift 4.1 Error throwing Test for associated values
enum ParseError: Error, Equatable {
case unexpectedArgument(String)
}
func testWithNoSchemaButWithOneArgument() {
XCTAssertThrowsError(try Args(withSchema: "", andArguments: ["-x"])) { error in
XCTAssertEqual(error as? ParseError, ParseError.unexpectedArgument("Argument(s) -x unexpected."))
}
}
【讨论】:
你可以使用这个功能:
func XCTAssertThrowsError<T, E: Error & Equatable>(
_ expression: @autoclosure () throws -> T,
error: E,
in file: StaticString = #file,
line: UInt = #line
) {
var thrownError: Error?
XCTAssertThrowsError(
try expression(),
file: file,
line: line) {
thrownError = $0
}
XCTAssertTrue(
thrownError is E,
"Unexpected error type: \(type(of: thrownError))",
file: file,
line: line
)
XCTAssertEqual(
thrownError as? E,
error,
file: file,
line: line
)
}
例子:
XCTAssertThrowsError(try funcThatThrowsSpecificError(), error: SpecificErrorEnum.someError)