Combine 系列
- Swift Combine 从入门到精通一
- Swift Combine 发布者订阅者操作者 从入门到精通二
- Swift Combine 管道 从入门到精通三
- Swift Combine 发布者publisher的生命周期 从入门到精通四
- Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五
- Swift Combine 订阅者Subscriber的生命周期 从入门到精通六
- Swift 使用 Combine 进行开发 从入门到精通七
- Swift 使用 Combine 管道和线程进行开发 从入门到精通八
- Swift Combine 使用 sink, assign 创建一个订阅者 从入门到精通九
- Swift Combine 使用 dataTaskPublisher 发起网络请求 从入门到精通十
- Swift Combine 用 Future 来封装异步请求 从入门到精通十一
- Swift Combine 有序的异步操作 从入门到精通十二
- Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三
- Swift Combine 网络受限时从备用 URL 请求数据 从入门到精通十四
- Swift Combine 通过用户输入更新声明式 UI 从入门到精通十五
- Swift Combine 级联多个 UI 更新,包括网络请求 从入门到精通十六
- Swift Combine 合并多个管道以更新 UI 元素 从入门到精通十七
- Swift Combine 通过包装基于 delegate 的 API 创建重复发布者 从入门到精通十八
- Swift Combine 响应NotificationCenter 的更新 从入门到精通十九
- Swift Combine 使用 ObservableObject 与 SwiftUI 模型作为发布源 从入门到精通二十
- Swift Combine 使用 XCTestExpectation 测试发布者 从入门到精通二十一
- Swift Combine 使用 PassthroughSubject 测试订阅者 从入门到精通二十二
1. 使用从 PassthroughSubject 预定好的发送的事件测试订阅者
目的:当你想要测试的是管道的时序时,用于测试管道或订阅者。
在 Combine 中有许多针对数据时序的操作符,包括 debounce
、throttle
以及 delay
。 在进行 UI 测试之外,你可能需要测试你的管道时序具有所需的效果。
实现这个的方法之一是利用 XCTestExpectation
和 passthroughSubject
,将两者结合起来。 基于 使用 XCTestExpectation
测试发布者 和 使用 PassthroughSubject
测试订阅者,在测试中添加 DispatchQueue
,以安排 PassthroughSubject
的 .send()
方法的调用。
一个这种用法的例子:
UsingCombineTests/PublisherTests.swift - testKVOPublisher
func testKVOPublisher() {
let expectation = XCTestExpectation(description: self.debugDescription)
let foo = KVOAbleNSObject()
let q = DispatchQueue(label: self.debugDescription) // 1
let _ = foo.publisher(for: \.intValue)
.print()
.sink { someValue in
print("value of intValue updated to: >>\(someValue)<<")
}
q.asyncAfter(deadline: .now() + 0.5, execute: { // 2
print("Updating to foo.intValue on background queue")
foo.intValue = 5
expectation.fulfill() // 3
})
wait(for: [expectation], timeout: 5.0) // 4
}
- 这将为你的测试添加
DispatchQueue
,并以测试的描述debugDescription
来命名该队列。 这只在调试中测试失败时显示,并且在还有其它后台线程也在使用时,方便地提醒测试代码中发生了什么情况。 .asyncAfter
和参数deadline
一起使用,用来定义何时发起请求.- 这是将任何相关的断言嵌入到订阅者或其周围的最简单的方式。此外,将
.fulfill()
作为你发送队列的最后一个条目,好让测试知道它现在已完成。 - 请确保当你设置等待超时时间时,有足够的时间让你的队列被调用。
此技术的一个明显缺点是,它使得测试花费的最短时间至少是测试中的最大的队列延迟。
另一种选择是第三方库,名为 EntwineTest
,开发灵感来自 RxTest
库。 EntwineTest
是 Entwine
的一部分,一个提供了一些 helpers
扩展了 Combine 的 Swift 库。 该库可以在 github 上找到,位于 https://github.com/tcldr/Entwine.git,只要使用时遵守 MIT 证书即可。
EntwineTest 中包含的关键元素之一是虚拟时间调度器,以及使用此调度器时安排(TestablePublisher
)并收集和记录(TestableSubscriber
)结果时间的其他类。
来自 EntwineTest 工程的 README 中的一个例子包含在:
UsingCombineTests/EntwineTestExampleTests.swift - testExampleUsingVirtualTimeScheduler
func testExampleUsingVirtualTimeScheduler() {
let scheduler = TestScheduler(initialClock: 0) // 1
var didSink = false
let cancellable = Just(1) // 2
.delay(for: 1, scheduler: scheduler)
.sink { _ in
didSink = true
}
XCTAssertNotNil(cancellable)
// where a real scheduler would have triggered when .sink() was invoked
// the virtual time scheduler requires resume() to commence and runs to
// completion.
scheduler.resume() // 3
XCTAssertTrue(didSink) // 4
}
- 使用虚拟时间调度器需要在测试开始时创建一个,将其时钟初始化为起始值。 EntwineTest 中的虚拟时间调度器将以 200 的值开始订阅,如果管道在时间为 900 时还没完成,则会超时。
- 你和以往创建任何发布者或订阅者一样,创建你的管道。 EntwineTest 还提供可测试的发布者和订阅者,以供使用。 有关 EntwineTest 这些部分的更多详细信息,请看 使用 EntwineTest 创建可测试的发布器和订阅者.
.resume()
需要在虚拟时间调度器上调用,以开始其工作和触发管道运行。- 在管道运行到完成后,对预期的最终结果进行断言。
参考
https://heckj.github.io/swiftui-notes/index_zh-CN.html
代码
https://github.com/heckj/swiftui-notes