1

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

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

3 回答 3

2

假设您的测试设置已经创建了一个视图控制器并调用loadViewIfNeeded()连接任何插座。(这来自第 5 章,“加载视图控制器”。)并且这个视图控制器位于我将命名的属性中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外面DispatchQueue.main.async呢?我在第 13 章“测试网络响应(和闭包)”中的“将异步代码保持在闭包中”一节中描述了这个问题。基本上,我们想要测试标签在分派的闭包没有运行时不会改变。我们可以通过第二个测试来做到这一点:

func test_setLabelText_withoutExecutingMainRunLoop_shouldNotUpdateLabel() throws {
    sut.label.text = "123"
    
    sut.setLabelText(msg: "TEST")
    
    XCTAssertEqual(sut.label.text, "123")
}
于 2020-11-26T18:06:01.320 回答
0

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

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

于 2020-11-02T06:53:59.300 回答
0

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

于 2020-11-02T09:17:38.090 回答