Swift 包 BCTest
提供了在 Swift 测试中断言异步条件的功能,其人体工程学设计与 XCTestExpectation
类似。
@Test @BCTest myTest() async throws {
let myNeed = await needManager.need(expectedCount: 1)
let myOtherNeed = await needManager.need(expectedCount: 1)
Task.detached {
myNeed.satisfy()
myOtherNeed.satisfy()
}
try await awaitSatisfaction(of: [myNeed, myOtherNeed], timeout: .infinity)
}
needManager
是 BCTestNeedManager
的一个实例。@BCTest
宏在 Swift 测试主体的顶部创建 needManager
。使用 needManager
来创建 BCTestNeed
的实例。
使用全局函数 awaitSatisfaction(of:timeout:)
等待 BCTestNeed
的满足。
所有已创建的 need 都必须被等待 (awaited) 且被满足 (satisfied),Swift 测试才能通过。@BCTest
宏将 await needManager.assertNeedsSatisfied()
添加到 Swift 测试主体的末尾。
展开后的宏
@Test @BCTest myTest() async throws {
let needManager = BCTestNeedManager() // *** ADDED BY MACRO ***
let myNeed = await needManager.need(expectedCount: 1)
let myOtherNeed = await needManager.need(expectedCount: 1)
Task.detached {
myNeed.satisfy()
myOtherNeed.satisfy()
}
try await awaitSatisfaction(of: [myNeed, myOtherNeed], timeout: .infinity)
await needManager.assertNeedsSatisfied() // *** ADDED BY MACRO ***
}
一个测试 need 被配置为期望零次或多次 satisfy()
的调用。一个测试 need 被配置为在过度满足 (over satisfied) 时是否失败。
一个 BCTestNeed
只能由一个 BCTestNeedManager
创建。
对 need 满足的断言只能由创建它的 need 管理器执行。
如果一个 need 永远不会被满足,则将其配置为 expectedCount: 0
。如果在 need 上调用 satisfy()
(例如,在不应该执行的代码路径中),该 need 将被过度满足,并且测试将失败。
如果一个测试被设计为 need 管理器的断言应该失败,请包含 .withKnownIssue
特性以避免测试失败,该特性将 need 管理器的断言包装在 withKnownIssue {..}
中。
BCTest
提供了以下不变性
注释:在等待结束后调用 satisfy()
会增加 need 的满足计数,但不能算作满足。
宏展开要求 BCTestNeedManager
的方法 init
和 assertNeedsSatisfied()
是公共的,但是你不应该创建另一个 need 管理器,因为宏不能确保 need 管理器断言满足并等待它创建的 need。
如果一个测试辅助函数创建了 need,请将宏提供的 needManager
传递给它。
建议使用 Confirmation
和 CheckedContinuation
在 Swift 测试中测试异步事件,但它们的人体工程学友好性不如 XCTest 的 XCTestExpectation
。
Confirmation
要求确认发生在它的 body
参数退出之前。await confirmation() { c in Task { c() } }
会失败,而 await confirmation() { c in await Task { c() }.value }
会通过。
CheckedContinuation
不需要在其 body
参数退出之前 resume()
。
await withCheckedContinuation { c in
Task {
let cookies = await chimChim.threwCookies()
#expect(cookies.count == 1)
c.resume()
}
}
但是 CheckedContinuation
只能 resume()
一次,因此无法在内部跟踪将要发生多次的事件。
此外,CheckedContinuation
需要小心,确保 resume()
在所有 @expect/#require
语句*之后*被调用,否则 Swift 测试上下文可能会错过它们。请参阅 Tests/AlternativeTests
中的 CheckedContinuationShouldFail
和 CheckedContinuationWithKnownIssue
测试。
最后,Confirmation
和 CheckedContinuation
与一个闭包以及闭包内发生的确认/延续具有 1:1 的关系。一个确保多个异步事件发生的测试可能需要嵌套这些结构的实例。
此包在 Unlicensed 许可证下发布。