Swift Power Assert

test workflow Build Status codecov

Power Assert(也称为图解断言)通过提供条件评估过程中产生的值的信息来增强断言失败信息,并以易于理解的形式呈现。 Power Assert是 Spock(以及后来的整个独立于Spock的 Groovy 语言),ScalaTestExpecty 中流行的功能。

Power Assert 为你的测试提供描述性的断言信息,如下面的例子所示:

#assert(numbers[2] == 4)
        │       ││ │  │
        │       │3 │  4
        │       2  false
        [1, 2, 3, 4, 5]

--- [Int] numbers[2]
+++ [Int] 4
–3
+4

[Int] numbers[2]
=> 3
[Int] 4
=> 4

#assert(numbers.contains(6))
        │       │        │
        │       false    6
        [1, 2, 3, 4, 5]

#assert(string1 == string2)
        │       │  │
        │       │  "Hello, Swift!"
        │       false
        "Hello, world!"

--- [String] string1
+++ [String] string2
Hello, {+S+}w[-orld-]{+ift+}!

[String] string1
=> "Hello, world!"
[String] string2
=> "Hello, Swift!"

在线 Playground

通过我们的在线 Playground 体验该库的功能! ✨ 点击这里访问交互式演示。

为什么选择 Power Assert?

在编写测试时,我们需要使用不同的断言函数。使用 Power Assert,你只需使用 #assert() 函数。 无需记住众多的断言 API。只需创建一个返回布尔值的表达式,Power Assert 将自动显示丰富的错误信息。

开始使用

要求

对于 Xcode 项目

要查看 PowerAssert 的实际效果,请转到 Examples 目录并运行 xcodebuild test ...

$ cd Examples/XcodeProject/
$ xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 14 Pro,OS=17.0' -parallel-testing-enabled NO

需要参数 -parallel-testing-enabled NO。 由于 Xcode 最近的更改,并行测试现在默认开启,测试信息不再输出到控制台。 因此,要查看控制台中的断言信息,请禁用并行测试。 启用并行测试后,所有控制台日志都可以从结果包中查看。

或者设置以下 UserDefaults。 此选项允许控制台输出,即使启用了并行测试。

defaults write com.apple.dt.xcodebuild ParallelTestRunnerStdoutMirroringEnabled -bool YES

对于 Swift Package Manager

要查看 PowerAssert 的实际效果,请转到 Examples 目录并运行 swift test

$ cd Examples/SwiftPackage/
$ swift test

看到以下结果了吗?

...
Test Suite 'All tests' started at 2023-04-05 07:17:58.800
Test Suite 'swift-power-assert-examplePackageTests.xctest' started at 2023-04-05 07:17:58.801
Test Suite 'PowerAssertTests' started at 2023-04-05 07:17:58.801
Test Case '-[ExampleTests.PowerAssertTests testExample]' started.
/swift-power-assert/Example/"ExampleTests/ExampleTests.swift":8: error: -[ExampleTests.PowerAssertTests testExample] : failed -
#assert(a * b == 91)
        │ │ │ │  │
        │ │ 9 │  91
        │ 90  false
        10

[Int] a
=> 10
[Int] b
=> 9
[Int] a * b
=> 90
[Int] 91
=> 91
/swift-power-assert/Example/"ExampleTests/ExampleTests.swift":11: error: -[ExampleTests.PowerAssertTests testExample] : failed -
#assert(xs.contains(4))
        │  │        │
        │  false    4
        [1, 2, 3]
...

修改 Example/Tests/ExampleTests.swift 中的代码以尝试你喜欢的不同模式。

用法

要在你的库或应用程序中使用 Swift Power Assert,首先将 swift-power-assert 添加到你的项目。

对于 Xcode 项目,将 swift-power-assert 库作为包依赖项添加。

选择 PowerAssert 作为 Package Product,并指定 Test Bundle 作为要添加的目标。

对于 Swift 包,请按如下方式配置 Package.swift

// swift-tools-version:5.9
import PackageDescription

let package = Package(
  name: "MyLibrary",
  dependencies: [
    ...,
    .package(
      url: "https://github.com/kishikawakatsumi/swift-power-assert.git",
      from: "0.12.0"
    ),
  ],
  targets: [
    ...,
    .testTarget(
      name: "MyLibraryTests",
      dependencies: [
        ...,
        .product(name: "PowerAssert", package: "swift-power-assert"),
      ]
    ),
  ]
)

接下来,你可以在测试中使用 #assert() 宏来使用 Power Assert。

// MyLibraryTests.swift
import XCTest
import PowerAssert
@testable import MyLibrary

final class MyLibraryTests: XCTestCase {
  func testExample() {
    let a = 7
    let b = 4
    let c = 12

    #assert(max(a, b) == c)
  }
}

并发 (async/await) 支持

Swift Power Assert 库允许你直接使用 async/await 表达式编写断言。 这是演示其对 async/await 无缝支持的示例代码

func testConcurrency() async {
  let ok = "OK"
  #assert(await upload(content: "example") == ok)
}

用于 CI

对于无人值守的使用(例如,在 CI 上),你可以通过以下方式禁用包验证对话框

常见问题解答

问:断言失败消息未显示。

如果你使用 xcodebuild test ... 命令从命令行运行测试,请禁用并行测试。 由于 Xcode 最近的更改,启用并行测试后,详细的测试日志不会输出到控制台。 使用以下选项禁用并行测试

-parallel-testing-enabled NO

或者,设置以下 UserDefaults。 此选项即使启用了并行测试,也能将详细的消息输出到控制台。

defaults write com.apple.dt.xcodebuild ParallelTestRunnerStdoutMirroringEnabled -bool YES

问:即使测试成功(即 #assert() 函数中的表达式的计算结果为 true),我也想显示结果。

答:默认情况下,如果表达式的计算结果为 true,则 #assert() 函数不会显示结果,因为测试已成功。 要始终打印结果,请将 verbose 参数设置为 true。

例如

#assert(x == y, verbose: true)

问:我想知道编译器实际上是如何扩展宏的。

答:你可以使用 -dump-macro-expansions 选项来转储宏扩展。

例如

$ cd Examples/SwiftPackage/
$ swift test -Xswiftc -Xfrontend -Xswiftc -dump-macro-expansions

如果你使用 -dump-macro-expansions 选项运行上述命令,你将获得以下输出。

...
@__swiftmacro_12ExampleTests011PowerAssertB0C04testA0yyF6assertfMf_.swift as ()
------------------------------
PowerAssert.Assertion("#assert(a * b == 91)", message: "", file: #""ExampleTests/ExampleTests.swift""#, line: 8, verbose: false, binaryExpressions: [0: "a", 2: "a * b", 3: "91", 1: "b"]) {
    $0.capture($0.capture($0.capture(a .self, column: 8, id: 0) * $0.capture(b .self, column: 12, id: 1), column: 10, id: 2) == $0.capture(91, column: 17, id: 3), column: 14, id: 4)
}
.render()
------------------------------
...

支持者 & 赞助商

开源项目的蓬勃发展离不开像你这样的人的慷慨支持。 如果你觉得这个项目有价值,请考虑扩展你的支持。 贡献项目不仅可以维持其增长,还可以帮助推动创新并改进其功能。

要支持此项目,你可以通过 GitHub Sponsors 成为赞助商。 你的贡献将不胜感激,并将有助于保持项目的活力和发展。 感谢你的考虑! ❤️

作者

Kishikawa Katsumi

许可证

该项目在 MIT 许可证 下发布