XCTAssertThrowsError 自定义错误处理程序的奇怪行为
XCTAssertThrowsError strange behavior with custom errorHandler
在我的单元测试中,我有以下代码检查抛出的错误是否属于预期类型。它是用两个相同的语句完成的,其中一个不能编译:
enum Error: ErrorType {
case SomeExpectedError
case SomeUnexpectedError
}
func functionThatThrows() throws {
throw Error.SomeExpectedError
}
// 1) this compiles fine
XCTAssertThrowsError(try functionThatThrows()) { (error) in
switch error {
case Error.SomeExpectedError: break
//everything is fine
case Error.SomeUnexpectedError: fallthrough
default:
XCTFail("Unexpected error thrown")
}
}
// 2) doesn't compiles at all
XCTAssertThrowsError(try functionThatThrows()) { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
第一个语句编译并运行良好,但第二个语句告诉我有两个错误:
Errors thrown from here are not handled
和 Cannot convert value of type '(Error) -> Void' to expected argument type 'String'
.
这段代码可能有什么问题?错误消息是什么意思?
我正在使用 Xcode 7.3 .
经过一些研究,我发现我的代码有 2 个问题:
1) 似乎我的闭包被认为是 "Impilictly returning" 因为它只包含一个可执行语句
2) 编译器对我的陈述感到困惑,因为 XCTAssertThows 接受了另一个接受闭包的参数 - 它是 @autoclosure _ message: () -> String
因此,编译器认为我传递了消息闭包(恕我直言,令人困惑的设计决定 - 将 @autoclosure 作为消息参数传递),而实际上我传递了 errorHandler 的闭包。
解决方法很简单:
// explicitly show closure returning type Void so that compiler couldn't
// use it as message argument (which closure must return String)
XCTAssertThrowsError(try functionThatThrows()) { (error) -> Void in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// explicitly show closure's argument type
XCTAssertThrowsError(try functionThatThrows()) { (error: ErrorType) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// use "message" parameter to preserve argument order
XCTAssertThrowsError(try functionThatThrows(), "some message") { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// wrap executable line in "do {}". I guess it works because closure stops
// being "implicitly returning" and now compiler treat it as () -> Void
// which is expected type of errorHandler argument
XCTAssertThrowsError(try functionThatThrows()) { (error) in
do {
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
}
我正在使用这个静态函数来测试特定异常:
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 = [=10=]
}
XCTAssertTrue(
thrownError is E,
"Unexpected error type: \(type(of: thrownError))",
file: file,
line: line
)
XCTAssertEqual(
thrownError as? E,
error,
file: file,
line: line
)
}
用法示例:
func testEmptyMrz() {
XCTAssertThrowsError(
try passportMrzValidator.validate(for: ""),
error: PassportMrzValidationError.invalidMrz
)
}
在我的单元测试中,我有以下代码检查抛出的错误是否属于预期类型。它是用两个相同的语句完成的,其中一个不能编译:
enum Error: ErrorType {
case SomeExpectedError
case SomeUnexpectedError
}
func functionThatThrows() throws {
throw Error.SomeExpectedError
}
// 1) this compiles fine
XCTAssertThrowsError(try functionThatThrows()) { (error) in
switch error {
case Error.SomeExpectedError: break
//everything is fine
case Error.SomeUnexpectedError: fallthrough
default:
XCTFail("Unexpected error thrown")
}
}
// 2) doesn't compiles at all
XCTAssertThrowsError(try functionThatThrows()) { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
第一个语句编译并运行良好,但第二个语句告诉我有两个错误:
Errors thrown from here are not handled
和 Cannot convert value of type '(Error) -> Void' to expected argument type 'String'
.
这段代码可能有什么问题?错误消息是什么意思?
我正在使用 Xcode 7.3 .
经过一些研究,我发现我的代码有 2 个问题:
1) 似乎我的闭包被认为是 "Impilictly returning" 因为它只包含一个可执行语句
2) 编译器对我的陈述感到困惑,因为 XCTAssertThows 接受了另一个接受闭包的参数 - 它是 @autoclosure _ message: () -> String
因此,编译器认为我传递了消息闭包(恕我直言,令人困惑的设计决定 - 将 @autoclosure 作为消息参数传递),而实际上我传递了 errorHandler 的闭包。
解决方法很简单:
// explicitly show closure returning type Void so that compiler couldn't
// use it as message argument (which closure must return String)
XCTAssertThrowsError(try functionThatThrows()) { (error) -> Void in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// explicitly show closure's argument type
XCTAssertThrowsError(try functionThatThrows()) { (error: ErrorType) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// use "message" parameter to preserve argument order
XCTAssertThrowsError(try functionThatThrows(), "some message") { (error) in
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
// wrap executable line in "do {}". I guess it works because closure stops
// being "implicitly returning" and now compiler treat it as () -> Void
// which is expected type of errorHandler argument
XCTAssertThrowsError(try functionThatThrows()) { (error) in
do {
XCTAssertEqual(error as? Error, Error.SomeExpectedError)
}
}
我正在使用这个静态函数来测试特定异常:
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 = [=10=]
}
XCTAssertTrue(
thrownError is E,
"Unexpected error type: \(type(of: thrownError))",
file: file,
line: line
)
XCTAssertEqual(
thrownError as? E,
error,
file: file,
line: line
)
}
用法示例:
func testEmptyMrz() {
XCTAssertThrowsError(
try passportMrzValidator.validate(for: ""),
error: PassportMrzValidationError.invalidMrz
)
}