我需要为以下方法编写单元测试
func setLabelText(msg: String) {
DispatchQueue.main.async {
self.label.text = msg
}
}
我需要为以下方法编写单元测试
func setLabelText(msg: String) {
DispatchQueue.main.async {
self.label.text = msg
}
}
假设您的测试设置已经创建了一个视图控制器并调用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")
}
您好,我认为使用XCTestExpectation
可能会受益,因为此 api 旨在测试异步操作(您可以在此处阅读有关它的更多信息)
就两者之间的比较而言,我唯一能想到的是,XCTestExpectation
您将能够测试服务器超时(假设您的 api 未在预期时间内响应。URLSession 的默认时间为 60 秒)具体的错误代码和消息。
您可以将完成闭包添加到 displayMessage 并在测试中调用expectation.fulfill()。另一种完全不同的方法是实现一些演示设计模式,如协调器或演示器。在这种情况下,您的所有 UI 表示将被抽象为非异步方法。