我有一个视图模型,其行为由Observable.interval
控制。实质上,它会更新每个next
上的计时器标签,并在一段时间后更新另一个值。
一个修剪过的例子:
class WorkoutViewModel {
private var _oneSecondTimer: Observable<Int> {
return Observable<Int>.interval(1, scheduler: MainScheduler.instance)
}
private let _exerciseRemainingTime: Variable<Int> = Variable(20)
func setupBehaviour() {
_oneSecondTimer.subscribeNext() { [unowned self] _ in
self._exerciseRemainingTime.value -= 1
if self._exerciseRemainingTime.value == 0 {
self.progressToNextExercise()
}
}
}
}
我想对此进行测试,以观察事件的时间和_exerciseRemainingTime
的值。
有没有办法如何使用TestScheduler
来模拟_oneSecondTimer
会勾选的虚拟时间?
答案 0 :(得分:7)
是的,请查看具有您正在寻找的行为的简单测试:https://github.com/ReactiveX/RxSwift/blob/b3f4bf1/Tests/RxSwiftTests/Tests/Observable+TimeTest.swift#L496
要将TestScheduler
换成MainScheduler
,我建议您将其作为依赖项注入。
另外,要检查_exerciseRemainingTime
的值,您需要删除private
。但是,我不建议测试你班级的内部。删除private
就是您的标志。相反,如果您要注入一个负责progressToNextExercise
的对象,那么您可以测试它是否接到了进行下一个练习的调用。您只需在测试期间传入该对象的测试版本,就像调度程序使用TestScheduler
一样。这样就无需公开_exerciseRemainingTime
来测试它,甚至不知道它。
但是,为了这个问题的主要目的,忽略了_exerciseRemainingTime
的可见性,这就是我对调度程序的意思:
WorkoutViewModel.swift
class WorkoutViewModel {
private var _oneSecondTimer: Observable<Int> {
return Observable<Int>.interval(1, scheduler: scheduler)
}
// not `private` anymore. also, a computed property
var _exerciseRemainingTime: Observable<Int> {
return self._oneSecondTimer.map { i in
20 - i
}
}
// injected via `init`
private let scheduler: SchedulerType
init(scheduler: SchedulerType) {
self.scheduler = scheduler
}
}
WorkoutViewModelTest.swift
func testExerciseRemainingTime() {
let scheduler = TestScheduler(initialClock: 0)
let res = scheduler.start(0, subscribed: 0, disposed: 23) {
WorkoutViewModel(scheduler: scheduler)._exerciseRemainingTime
}
let correct = [
next(1, 20), // output .Next(20) at 1 second mark
next(2, 19), // output .Next(19) at 2 second mark
next(3, 18),
next(4, 17),
next(5, 16),
next(6, 15),
next(7, 14),
next(8, 13),
next(9, 12),
next(10, 11),
next(11, 10),
next(12, 9),
next(13, 8),
next(14, 7),
next(15, 6),
next(16, 5),
next(17, 4),
next(18, 3),
next(19, 2),
next(20, 1),
next(21, 0),
next(22, -1),
]
XCTAssertEqual(res.events, correct)
}
要考虑几个注意事项:
为了让测试调度程序订阅和处置,我从视图模型中删除了subscribeNext
。我认为这无论如何都会改进它,因为您应该使用视图控制器订阅并仅使用视图模型为您提供Observable
。这样就不需要视图模型具有一个配置包并管理Disposable
的生命周期。
你应该考虑更少地暴露内容&#34;内部&#34;比_exerciseRemainingTime
。也许像currentExercise: Observable<ExerciseEnum>
这样的内容基于_exerciseRemainingTime
。这样,您的视图控制器可以订阅并执行与视图控制器相关的简单工作,即可进行下一个练习。
另外,为了简化测试,您可以将20
变量注入视图模型,这样在测试中您可以提供像3
那样较小的内容,然后correct
只需要是一些元素。