ExpectToEventuallyEqual

Build Mastodon Follow

ExpectToEventuallyEqual 是一个用于异步代码的 XCTest 断言。

目录

示例

假设我们有一个从视图模型读取数据的表格视图。视图模型决定了表格中的行数

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    results.count
}

代码片段源文件 | 锚点

表格视图控制器的 viewDidLoad() 方法告诉视图模型加载数据,然后重新加载表格数据。 因为 load() 是异步的,所以我们等待它的结果并将它包装在 Task 中。

Task {
    results = await viewModel.load()
    self.tableView.reloadData()
}

代码片段源文件 | 锚点

如果此 Task 包含对闭包的调用,则测试可以等待 XCTestExpectation 并注入一个闭包,该闭包调用期望上的 fulfill()。 因此,测试此方法的一种方法是添加一个完成闭包,该闭包在数据重新加载后触发。

另一种方法是以周期性间隔检查某些条件。 在将两个结果存根到视图模型后,这是一个 expectToEventuallyEqual 断言,它检查行数最终是否为 2

try await expectToEventuallyEqual(
    actual: { tableDataSource.tableView(sut.tableView, numberOfRowsInSection: 0) },
    expected: 2
)

代码片段源文件 | 锚点

该断言重复计算 actual 闭包,并将其与 expected 值进行比较。 只要它们相等,此断言就会通过。 如果超时且值仍然不相等,则断言失败。

Example failure says test_numberOfRows(): failed - Expected 2, but was 1 after 93 tries, timing out after 1.0 seconds

有一个 SampleApp 你可以尝试查看一些通过的测试和一个失败的测试。

如何安装

Swift Package Manager

如果您有一个 Project.swift 文件,请声明以下依赖项

dependencies: [
    .package(url: "https://github.com/jonreid/ExpectToEventuallyEqual", from: "1.0.0"),
],

然后将其添加到您的测试目标中

.testTarget(
    name: "MyTests",
    dependencies: [
        "ExpectToEventuallyEqual",
    ],

详情

允许 actual 闭包抛出异常。

actual 闭包和 expected 值必须计算为相同的 Equatable 类型。

默认 timeout 为 1 秒。您可以指定不同的值。

每次比较后,RunLoop 会短暂运行以处理线程上的其他事件。

失败时,断言报告预期值和最后实际值。 如果它们是字符串,则这些值显示在双引号中,以下字符表示为转义特殊字符

起源

Jon Reid 和 Steven Baker 在一起教授 iOS 研讨会时创建了这个断言。