Swift Combine 使用 XCTestExpectation 测试发布者 从入门到精通二十一

Combine 系列

  1. Swift Combine 从入门到精通一
  2. Swift Combine 发布者订阅者操作者 从入门到精通二
  3. Swift Combine 管道 从入门到精通三
  4. Swift Combine 发布者publisher的生命周期 从入门到精通四
  5. Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五
  6. Swift Combine 订阅者Subscriber的生命周期 从入门到精通六
  7. Swift 使用 Combine 进行开发 从入门到精通七
  8. Swift 使用 Combine 管道和线程进行开发 从入门到精通八
  9. Swift Combine 使用 sink, assign 创建一个订阅者 从入门到精通九
  10. Swift Combine 使用 dataTaskPublisher 发起网络请求 从入门到精通十
  11. Swift Combine 用 Future 来封装异步请求 从入门到精通十一
  12. Swift Combine 有序的异步操作 从入门到精通十二
  13. Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三
  14. Swift Combine 网络受限时从备用 URL 请求数据 从入门到精通十四
  15. Swift Combine 通过用户输入更新声明式 UI 从入门到精通十五
  16. Swift Combine 级联多个 UI 更新,包括网络请求 从入门到精通十六
  17. Swift Combine 合并多个管道以更新 UI 元素 从入门到精通十七
  18. Swift Combine 通过包装基于 delegate 的 API 创建重复发布者 从入门到精通十八
  19. Swift Combine 响应NotificationCenter 的更新 从入门到精通十九
  20. Swift Combine 使用 ObservableObject 与 SwiftUI 模型作为发布源 从入门到精通二十
    在这里插入图片描述

1. 测试和调试

Combine 中的发布者和订阅者接口是非常易于测试的。

借助 Combine 的可组合性,你可以利用此优势创建或消费符合 Publisher 协议的 API。

publisher protocol 为关键接口,你可以替换任何一方以单独验证你的代码。

例如,如果你的代码专注于通过 Combine 从外部 Web 服务中提供其数据,则可能会使此接口遵循 AnyPublisher<Data, Error>。 然后,你可以使用该接口独立测试管道的任何一侧。

  • 你可以模拟 API 请求和可能响应的数据,包括各种错误条件。 这可以包括使用 JustFail 创建的发布者来返回数据,或者更复杂的使用 Future。 使用这些方案都不需要你进行实际的网络接口调用。

  • 同样,你也可以隔离测试,让发布者进行 API 调用,并验证预期的各种成功和失败条件。

2. 使用 XCTestExpectation 测试发布者

目的:用于测试发布者(以及连接的任何管道)

当你测试发布者或创建发布者的某些代码时,你可能无法控制发布者何时返回数据以进行测试。 由其订阅者驱动的 Combine 可以设置一个同步事件来启动数据流。 你可以使用 XCTestExpectation 等待一段确定的时间之后,再调用 completion 闭包进行测试。

此与 Combine 一起使用的模式:

  1. 在测试中设置 expectation。
  2. 确定要测试的代码。
  3. 设置要调用的代码,以便在执行成功的情况下,你调用 expectation 的 .fulfill() 函数。
  4. 设置具有明确超时时间的 wait() 函数,如果 expectation 在该时间窗口内未调用 fulfill(),则测试将失败。

如果你正在测试管道中的结果数据,那么在 sink 操作符的 receiveValue 闭包中触发 fulfill() 函数是非常方便的。 如果你正在测试管道中的失败情况,则通常在 sink 操作符的 receiveCompletion 闭包中包含 fulfill() 方法是有效的。

下列示例显示使用 expectation 测试一次性发布者(本例中是 URLSession.dataTaskPublisher),并期望数据在不出错的情况下流动。

UsingCombineTests/DataTaskPublisherTests.swift - testDataTaskPublisher

func testDataTaskPublisher() {
        // setup
        let expectation = XCTestExpectation(description: "Download from \(String(describing: testURL))")  // 1
        let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: self.testURL!)
            // validate
            .sink(receiveCompletion: { fini in
                print(".sink() received the completion", String(describing: fini))
                switch fini {
                case .finished: expectation.fulfill()  // 2
                case .failure: XCTFail()  // 3
                }
            }, receiveValue: { (data, response) in
                guard let httpResponse = response as? HTTPURLResponse else {
                    XCTFail("Unable to parse response an HTTPURLResponse")
                    return
                }
                XCTAssertNotNil(data)
                // print(".sink() data received \(data)")
                XCTAssertNotNil(httpResponse)
                XCTAssertEqual(httpResponse.statusCode, 200)  // 4
                // print(".sink() httpResponse received \(httpResponse)")
            })

        XCTAssertNotNil(remoteDataPublisher)
        wait(for: [expectation], timeout: 5.0)  // 5
    }
  1. Expectation 设置为一个字符串,这样在发生失败时更容易调试。 此字符串仅在测试失败时才能看到。 我们在这里测试的代码是 dataTaskPublisher 从测试前就已定义好的预设的 URL 中取回数据。 发布者通过将 sink 订阅者连接到它开始触发请求。 如果没有 expectation,代码仍将运行,但构建的测试运行结构将不会等到结果返回之后再去检查是否有任何意外。 测试中的 expectation “暂停测试” 去等待响应,让操作符先发挥它们的作用。
  2. 在这个例子中,测试期望可以成功完成并正常终止,因此在 receiveCompletion 闭包内调用 expectation.fulfill(),具体是接收到 .finished completion 后调用。
  3. 由于我们不期望失败,如果我们收到 .failure completion,我们也明确地调用 XCTFail()
  4. 我们在 receiveValue 中还有一些其他断言。 由于此发布者设置返回单个值然后终止,因此我们可以对收到的数据进行内联断言。 如果我们收到多个值,那么我们可以收集这些值,并就事后收到的内容做出断言。
  5. 此测试使用单个 expectation,但你可以包含多个独立的 expectation,去要求它们都被 fulfill()。 它还规定此测试的最长运行时间为 5 秒。 测试并不总是需要五秒钟,因为一旦收到 在这里插入代码片fulfill,它就会完成。 如果出于某种原因,测试需要超过五秒钟的响应时间,XCTest 将报告测试失败。

参考

https://heckj.github.io/swiftui-notes/index_zh-CN.html

代码

https://github.com/heckj/swiftui-notes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值