VirtualTimeScheduler(虚拟时间调度器)

一个 Combine 调度器,它基于虚拟时钟执行操作。非常适合测试自定义 Publisher 或测试时间相关的 Pub-Sub 代码。

该调度器将在“虚拟”时钟的基础上,在预定时间运行计划的操作。可以使用以下方法之一调整调度器的时钟。

操作可以调度其他操作。 如果这些操作已到期,调度器将在同一次时间更新调用中运行这些操作。

Combine 通过以下方法提供调度 publisher 的功能。

使用这些方法的代码的测试需要等待事件发生。 当使用 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

编辑 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
            ]),
    ]
)

对于 .xcodeproj 项目

  1. 打开菜单 File > Add Packages...
  2. 搜索 "https://github.com/berikv/VirtualTimeScheduler.git" 并单击 Add Package。
  3. 打开你的项目文件,在 “Targets” 中选择你的目标。
  4. 打开 Dependencies
  5. 点击 + 号
  6. 添加 VirtualTimeScheduler