如何对强制展开进行单元测试
Posted
技术标签:
【中文标题】如何对强制展开进行单元测试【英文标题】:How to unit test a forced unwrapping 【发布时间】:2015-07-21 10:24:59 【问题描述】:在带有 XCTest 的 Swift 中,是否可以测试强制展开的结果?我希望像 Jasmine 的 expect(...).toThrow()
:
let a: Something? = MAYBE_NIL_MAYBE_NOT
func unwrap()
a!
XCTAssertCausesError(unwrap)
【问题讨论】:
XCTAssert(a == nil)
让我修改问题:)
如果要保证value-a不应该为nil,可以使用XCTAssertNotNil
。如果要确保为nil,可以使用XCTAssertNil
@iosDev82 在这种情况下,问题是关于捕获因强制解包失败而导致的错误。
【参考方案1】:
使用新的XCTUnwrap
解包对象,如果值为 nil 则断言。
let optional: String? = "optional"
let unwrapped: String = try XCTUnwrap(optional) // throws
在非抛出函数中,您可以将guard
用于测试失败的单行,如下所示:
guard let unwrapped = try? XCTUnwrap(optional) else return
这与测试强制展开基本相同。只需使用函数而不是!
。
XCTUnwrap
断言 Optional 变量的值不为 nil,如果断言成功则返回其值。这消除了将
XCTAssertNotNil(_:_:file:line:)
与解包值或处理其余测试的条件链接的需要。例如:
func testFirstNameNotEmpty() throws
let forenames: [String] = customer.forenames
let firstName = try XCTUnwrap(forenames.first)
XCTAssertFalse(firstName.isEmpty)
在 WWDC 2019 和 Xcode 11 发行说明中宣布:https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes
【讨论】:
谢谢@pkamb,这看起来很完美,我已经更改了接受的答案。【参考方案2】:根据 swift 的定义,您无法捕获强制解包失败。另外,我不认为在生产代码中使用强制解包是一个好主意,除非你绝对确定它不会失败。
如果你使用,你会得到一个解包异常:
guard let a = a else throw ...
而不是a!
【讨论】:
很好地解释了为什么使用强制展开不是一个好主意。但是,如果可以对其进行测试,那么我们可以(合理地)确定它不会发生,并且比警卫引入的详细程度要少。【参考方案3】:我没有明确的答案,但Apple's documentation 强制展开值表示以下内容:
注意 尝试使用!访问不存在的可选值会触发运行时错误。在使用之前,请务必确保可选项包含非零值!强制解包其值。
swift 语言 (2.0) 目前没有语法来捕获这些runtime error
s。这些可能等同于不会被 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))
【讨论】:
很好的解释。这很好,除了计算变量还不能使用 throw(因此保护),所以可测试的代码现在必须使用 getter 函数。谢谢。以上是关于如何对强制展开进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章
Angular:运行Git push时如何强制运行单元测试?
PHPstorm配置PHPunit对composer引入的php代码进行单元测试