繁体   English   中英

如何测试在 Swift 中异步调度工作的方法

[英]How to test method that dispatch work asynchronously in Swift

我需要为以下方法编写单元测试

func setLabelText(msg: String) {
     DispatchQueue.main.async {
          self.label.text = msg
      }
  }

让我们假设您的测试设置已经创建了一个视图控制器并调用loadViewIfNeeded()来连接任何插座。 (这是来自第 5 章“加载视图控制器”。)而且这个视图控制器位于我将命名为sut (意思是sut系统)的属性中。

如果您编写测试用例来调用setLabelText(msg:) ,然后立即检查视图控制器的标签,这将不起作用。

如果你有一个后台线程的分派,那么我们需要测试来等待线程完成。 但对于这段代码,情况并非如此。

您的生产代码从后台调用setLabelText(msg:) 但是测试代码在主线程上运行。 由于它已经在主线程上,我们需要做的就是再执行一次运行循环。 您可以使用我在第 10 章“测试屏幕间导航”中介绍的辅助函数来表达这一点:

func executeRunLoop() {
    RunLoop.current.run(until: Date())
}

有了这个,这是一个有效的测试:

func test_setLabelText_thenExecutingMainRunLoop_shouldUpdateLabel() throws {
    sut.setLabelText(msg: "TEST")
    executeRunLoop()
    
    XCTAssertEqual(sut.label.text, "TEST")
}

这成功地测试了该方法,并快速完成。 但是,如果另一个程序员出现并更改setLabelText(msg:) ,将self.label.text = msg调用self.label.text = msg DispatchQueue.main.async之外呢? 我在第 13 章“测试网络响应(和闭包)”中的“保持异步代码处于闭包状态”一节中描述了这个问题。 基本上,我们想测试当分派的闭包没有运行时标签不会改变。 我们可以通过第二个测试来做到这一点:

func test_setLabelText_withoutExecutingMainRunLoop_shouldNotUpdateLabel() throws {
    sut.label.text = "123"
    
    sut.setLabelText(msg: "TEST")
    
    XCTAssertEqual(sut.label.text, "123")
}

您好,我认为使用XCTestExpectation可能会受益,因为此 api 旨在测试异步操作(您可以在此处阅读有关它的更多信息)

就两者之间的比较而言,我唯一能想到的是使用XCTestExpectation您将能够测试服务器超时(假设您的 api 没有在预期时间内响应。URLSession 的默认时间为 60 秒)带有特定的错误代码和消息。

您可以将完成闭包添加到 displayMessage 并在测试中调用 expect.fulfill() 。 另一种完全不同的方法是实现一些演示设计模式,如协调器或演示者。 在这种情况下,您的所有 UI 表示都将被抽象为非异步方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM