遅延が発生するObservable
を単体テストできるようにしたいが、実際には遅延時間を待たない。これを行う方法はありますか?
現在CountDownHatchを使用してアサートを遅延させていますが、これは問題なく機能しますが、テストの実行時間が長くなります。
例:
val myObservable: PublishSubject<Boolean> = PublishSubject.create<Boolean>()
fun myObservable(): Observable<Boolean> = myObservable.delay(3, TimeUnit.SECONDS)
@Test
fun testMyObservable() {
val testObservable = myObservable().test()
myObservable.onNext(true)
// val lock = CountDownLatch(1)
// lock.await(3100, TimeUnit.MILLISECONDS)
testObservable.assertValue(true)
}
@ aaron-heの回答のおかげで、完全な解決策を見つけることができました。
TestScheduler
の組み合わせを使用して時間を進め、RxJavaPlugins
を使用してデフォルトのスケジューラーをtestSchedulerでオーバーライドします。これにより、変更せずにmyObservable()
関数をテストしたり、Scheduler
を渡す必要がなくなりました。
@Before
fun setUp() = RxJavaPlugins.reset()
@After
fun tearDown() = RxJavaPlugins.reset()
@Test
fun testMyObservable() {
val testScheduler = TestScheduler()
RxJavaPlugins.setComputationSchedulerHandler { testScheduler }
val testObservable = myObservable().test()
myObservable.onNext(true)
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
testObservable.assertEmpty()
testScheduler.advanceTimeBy(2, TimeUnit.SECONDS)
testObservable.assertValue(true)
}
TestScheduler
はこれに最適です。便利なメソッドadvanceTimeBy(long, TimeUnit)
があり、タイミングを制御できます。また、_Observable.delay
_には オーバーロードメソッド があり、Scheduler
を受け取ります。
したがって、myObservable
関数でデフォルトのScheduler.computation()
を使用し、単体テストではTestScheduler
を使用します。
PublishSubject
の奇妙な動作が見つかりました。サブスクライブにしばらく時間がかかります。たとえば、テストが失敗します:
_private val scheduler = TestScheduler()
@Test
fun publishSubjectFailedTest() {
val callback: DelayCallback = mock()
val myPublishSubject: PublishSubject<Boolean> = PublishSubject.create()
myPublishSubject
.delay(10, TimeUnit.SECONDS, scheduler)
.subscribeOn(scheduler)
.observeOn(scheduler)
.subscribe(
Consumer<Boolean> {
callback.onCalldown()
},
Consumer<Throwable> {
},
Action {
}
)
myPublishSubject.onNext(true)
scheduler.advanceTimeBy(20, TimeUnit.SECONDS)
verify(callback, times(1)).onCalldown()
}
_
しかし、scheduler
を呼び出す前にonNext
の時間を追加した場合、たとえばscheduler.advanceTimeBy(1, TimeUnit.NANOSECONDS)
の場合、テストは成功します。
_ @Test
fun publishSubjectSuccessTest() {
val callback: DelayCallback = mock()
val myPublishSubject: PublishSubject<Boolean> = PublishSubject.create()
myPublishSubject
.delay(10, TimeUnit.SECONDS, scheduler)
.subscribeOn(scheduler)
.observeOn(scheduler)
.subscribe(
Consumer<Boolean> {
callback.onCalldown()
},
Consumer<Throwable> {
},
Action {
}
)
scheduler.advanceTimeBy(1, TimeUnit.NANOSECONDS)//added time of scheduler
myPublishSubject.onNext(true)
scheduler.advanceTimeBy(20, TimeUnit.SECONDS)
verify(callback, times(1)).onCalldown()
}
_