如何对强制展开进行单元测试

How to unit test a forced unwrapping

在 Swift 中使用 XCTest,是否可以测试强制展开的结果?我希望像 Jasmine 的 expect(...).toThrow():

let a: Something? = MAYBE_NIL_MAYBE_NOT

func unwrap()
{
    a!
}

XCTAssertCausesError(unwrap)

根据 swift 中的定义,您无法捕获强制解包失败。另外,我不认为在生产代码中使用强制解包是个好主意,除非你绝对确定它不会失败。

如果你使用:

你会得到一个解包异常
 guard let a = a else { throw ... }

而不是a!

我没有明确的答案,但 Apple's documentation 关于强制解包值的说法如下:

NOTE
Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value.

swift 语言 (2.0) 当前没有语法来捕获这些 runtime error。这些可能等同于分段 faults/kills,它不会被 Objective-C 的 @try/@catch 语法所困。

您似乎也在测试语言的功能本身(即强制展开 nil 值会引发异常),而不是您的应用逻辑。您最好按照@Mario Zannone 的建议赶上 throw

let a: Something? = MAYBE_NIL_MAYBE_NOT

func unwrap(test: Any?)
{
    guard let value = test else {
        throw // an ErrorType
    }
}

XCTAssertCausesError(unwrap(a))

使用新的 XCTUnwrap 解包对象并断言值为 nil。

let optional: String? = "optional"
let unwrapped: String = try XCTUnwrap(optional) // throws

在非抛出函数中,您可以将 guard 用于测试失败的单行代码,如下所示:

guard let unwrapped = try? XCTUnwrap(optional) else { return }

这与测试强制展开基本相同。只需使用函数而不是 !.

XCTUnwrap asserts that an Optional variable’s value is not nil, returning its value if the assertion succeeds.

This removes the need to combine XCTAssertNotNil(_:_:file:line:) with either unwrapping the value or dealing with conditional chaining for the rest of the test. For example:

func testFirstNameNotEmpty() throws {
    let forenames: [String] = customer.forenames

    let firstName =  try XCTUnwrap(forenames.first)
    XCTAssertFalse(firstName.isEmpty)
}

在 WWDC 2019 和 Xcode11 发行说明中宣布:
https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes