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

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 errors。这些可能等同于不会被 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 函数。谢谢。

以上是关于如何对强制展开进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySql 中对事务提交超时进行单元测试?

Angular:运行Git push时如何强制运行单元测试?

PHPstorm配置PHPunit对composer引入的php代码进行单元测试

使用计算的返回值进行单元测试展开 segue

如何从 Java 单元测试中捕获或强制执行 REST API 覆盖?

iOS 单元测试:如何对 firstResponderStatus 进行单元测试