【发布时间】:2021-10-07 05:14:15
【问题描述】:
我创建了一个使用ObservableObject 的视图,该视图使用Timer 更新作为@Published 属性的秒数。
class TimerService: ObservableObject {
@Published var seconds: Int
var timer: Timer?
convenience init() {
self.init(0)
}
init(_ seconds: Int){
self.seconds = seconds
}
func start() {
...
self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.seconds += 1 }
self.timer?.fire()
}
func stop() {...}
func reset() {...}
}
为了测试这个逻辑,我尝试订阅seconds var。问题是 .sink 方法只会触发一次,并且永远不会再次触发,即使它应该触发也是如此。
class WorkTrackerTests: XCTestCase {
var timerService: TimerService!
override func setUpWithError() throws {
super.setUp()
timerService = TimerService()
}
override func tearDownWithError() throws {
super.tearDown()
timerService = nil
}
func test_start_timer() throws {
var countingArray: [Int] = []
timerService.start()
timerService.$seconds.sink(receiveValue: { value -> Void in
print(value) // 1 (called once with this value)
countingArray.append(value)
})
timerService.stop()
for index in 0...countingArray.count-1 {
if(index>0) {
XCTAssertTrue(countingArray[index] - 1 == countingArray[index-1])
}
}
}
}
是我做错了什么还是 SwiftUI @Published Wrapper 不能被 SwiftUI 本身以外的其他东西订阅?
【问题讨论】:
-
无需测试苹果的代码。不要测试计时器。你知道它的作用。测试你的代码。
-
至于您的实际示例测试工具,它从上到下都有缺陷。没有
store的sink确实只会得到一个值,如果它得到任何值的话。但是这个问题会更深层次,因为你的行为就像你的代码会神奇地停止并等待计时器完成。它不会。你说开始后立即停止。异步输入需要异步测试。你需要一个期望和一个服务员。 -
但您完全不清楚为什么要订阅出版商。你想知道什么?似乎唯一感兴趣的问题是每次计时器触发时是否都在增加变量。您可以在没有计时器且无需订阅发布者的情况下进行测试。
-
@matt 我想确保计时器不会以某种方式工作。它基本上是一个进入 MacOS SwiftUI 测试的测试。你能提供一个如何测试这个异步的例子吗?我在网上找不到解决方案:(
-
计时器如何停止工作?同样,您不能/不应该测试 Timer。你知道它的作用,它不是你的。