如何在 Swift 中编写单元测试,以便在调用可能抛出异常的函数时传达有用的信息?
我真正希望能够做的是这样的:
class TestTestsTests: XCTestCase {
func doFoo() throws -> String {
// A complex operation that might throw in various places
return "foo"
}
func doBar() throws -> String {
// A complex operation that might throw in various places
return "bar"
}
func testExample() throws {
let foo = try doFoo()
let bar = try doBar()
XCTAssertNotEqual(foo, bar)
}
}
理想情况下,单元测试运行程序将停止在发生未处理异常的行上,并让用户探索堆栈和错误消息。不幸的是,添加throws
到测试函数会导致它被默默地跳过(并且有一个 UI 错误,使得测试看起来好像仍在运行,并且得到与添加 throws
之前相同的结果)。
当然也可以这样做:
func testExample() {
let foo = try! doFoo()
let bar = try! doBar()
XCTAssertNotEqual(foo, bar)
}
但是现在失败并不能真正提供我们需要的上下文。添加throw
至doFoo
,我们收到类似 fatal error: 'try!' expression unexpectedly raised an error: TestTestsTests.Error(): file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.1.101.15/src/swift/stdlib/public/core/ErrorType.swift, line 50
的消息,它只给我们 testExample
范围内的行号,并且不在 doFoo
范围内发生错误的地方。无论是否启用断点,这似乎也会使调试器“卡住”(单击“继续”只会返回到具有相同错误消息的同一行),并阻止其他测试运行。
那么也许我们可以尝试这样的事情?
func testExample() {
do {
let foo = try doFoo()
let bar = try doBar()
XCTAssertNotEqual(foo, bar)
} catch {
XCTFail("\(error)")
}
}
这按预期运行,但是我们无法确定 doFoo
中的哪一个或doBar
抛出错误,也没有行号信息。至少我们可以得到错误消息并且不阻止其他测试的运行。
我可以继续,但缺点是我找不到一种方法来同时不中断单元测试的运行(如 try!
),找出哪个函数引发了错误,并得到错误信息——除非我做了一些荒谬的事情,比如:
func testExample() {
var foo: String? = nil
var bar: String? = nil
do {
foo = try doFoo()
} catch {
XCTFail("\(error)")
return
}
do {
bar = try doBar()
} catch {
XCTFail("\(error)")
return
}
if let foo = foo, bar = bar {
XCTAssertNotEqual(foo, bar)
}
}
我仍然不知道doFoo
在哪里或doBar
发生错误。
这只是 Swift 单元测试的悲惨状态,还是我错过了什么?
最佳答案
This runs as expected, however we can't determine which of doFoo or doBar threw the error, and also no line number information.
也许这只是一个老问题,或者我不理解你的问题,或者你只是在发表声明而不是提出问题。但对于上面引用的声明,您可以将任何您喜欢的信息添加到 XCTest 断言中的消息中。 Swift 还提供了以下文字:
#file String Name of the file where this literal appears.
#line Int The line number on which it appears.
#column Int The column number in which it begins.
#function String The name of the declaration in which it appears.
func testExample() {
var foo: String? = nil
var bar: String? = nil
do {
foo = try doFoo()
} catch {
XCTFail("try doFoo() failed on line: \(#line) in file: \(#file) with error: \(error)")
return
}
do {
bar = try doBar()
} catch {
XCTFail("try doBar() failed on line: \(#line) in file: \(#file) with error: \(error)")
return
}
if let foo = foo, bar = bar {
XCTAssertNotEqual(foo, bar)
}
}
如果您真的想疯狂地使用它,您可以向 doBar() 方法添加错误处理,并且该错误可以包含您想要的任何内部信息。 事实上......通过在方法中实现您自己的错误,您甚至可能不需要在测试中将方法分成两个 block ,只需打印错误就足够了。您可以在错误消息中添加任何您喜欢的信息。
不管怎样,我认为这是一个过时的问题,你可以从测试日志中获取你需要的所有信息 - 它们列出了所有失败的方法,甚至有小箭头让你直接跳到失败的测试。然后他们强调失败的具体断言……从那里很容易看出大多数情况下发生了什么。最坏的情况是您必须设置一两个断点并再次运行测试。关于ios - Swift:使用抛出异常的函数进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35324505/