Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing Rxjava observables that have a delay

I want to be able to unit test an Observable that has a delayed emission, but without actually waiting for the delay time. Is there a way to do this?

I'm currently using a CountDownHatch to delay the assert, and that works fine, but increases the test run time.

Example:

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)
}
like image 535
triad Avatar asked Nov 14 '17 23:11

triad


1 Answers

I was able to come up with a complete solution thanks to @aaron-he's answer.

It uses a combination of TestScheduler to advance the time and also RxJavaPlugins to override the default scheduler with the testScheduler. This allowed testing the myObservable() function without modification or needing to pass in a 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)
}
like image 109
triad Avatar answered Oct 02 '22 15:10

triad