一个 Combine 调度器,它基于虚拟时钟执行操作。非常适合测试自定义 Publisher 或测试时间相关的 Pub-Sub 代码。
该调度器将在“虚拟”时钟的基础上,在预定时间运行计划的操作。可以使用以下方法之一调整调度器的时钟。
run()
- 运行直到没有更多计划的操作step()
- 将时间设置为第一个到期操作的到期时间advanceTime(by:)
- 将内部时钟推进指定的量setTime(to:)
- 将时间设置为一个值,时钟从 .referenceTime
开始操作可以调度其他操作。 如果这些操作已到期,调度器将在同一次时间更新调用中运行这些操作。
Combine 通过以下方法提供调度 publisher 的功能。
delay(for:tolerance:scheduler:options:)
debounce(for:scheduler:options:)
throttle(for:scheduler:latest:)
使用这些方法的代码的测试需要等待事件发生。 当使用 RunLoop 或 DispatchQueue 调度器时,测试将花费实际时间(wall-clock time)。这意味着你的测试需要更长时间。
VirtualTimeScheduler 允许在不花费实际时间的情况下测试此类代码。
step()
查找下一个到期的操作,并将时间更新到该操作的到期时间,并运行所有在该新时间之前到期的操作。
run
方法逐步增加虚拟时间,直到所有计划的操作都已完成。
“3 秒后”指的是“虚拟时间”。
let scheduler = VirtualTimeScheduler()
let cancellable = Just(42)
.delay(for: .seconds(3), scheduler: scheduler)
.measureInterval(using: scheduler)
.sink { value in
print("Received \(value.magnitude) seconds later")
}
print("Before run \(Date())")
scheduler.run()
print("After run \(Date())")
// Before run 2022-01-20 14:13:11 +0000
// Received 3.0 seconds later
// After run 2022-01-20 14:13:11 +0000
advanceTime(by:)
方法推进虚拟时间,并运行任何在该新时间之前到期的计划操作。
let scheduler = VirtualTimeScheduler()
let subject = PassthroughSubject<Int, Never>()
let cancellable = subject
.debounce(for: .seconds(1), scheduler: scheduler)
.sink { value in
let timeInterval = scheduler.now.timeIntervalSinceReferenceTime
print("Received \(value), \(timeInterval) seconds later")
}
for value in 0..<4 {
subject.send(value)
scheduler.advanceTime(by: .seconds(0.1))
}
scheduler.advanceTime(by: .seconds(1))
for value in 4..<8 {
subject.send(value)
scheduler.advanceTime(by: .seconds(0.1))
}
scheduler.advanceTime(by: .seconds(1))
_ = cancellable
// Prints:
// Received 3, 1.4 seconds later
// Received 7, 2.8 seconds later
也可以使用 setTime(to:)
直接设置时间。
编辑 Package.swift 文件。 将 VirtualTimeScheduler 添加为依赖项
let package = Package(
name: " ... ",
products: [ ... ],
dependencies: [
.package(url: "https://github.com/berikv/VirtualTimeScheduler.git", from: "1.0.0") // here
],
targets: [
.target(
name: " ... ",
dependencies: [
"VirtualTimeScheduler" // and here
]),
]
)