Jefferson Setiawan
Jefferson Setiawan

Reputation: 536

How to unit test RxSwift which has debounce before output the next?

I am using RxSwift for reactive programming and want to test my View Model. I have debounce like this:

In View Model:

let personNameMessage = input.personName.debounce(0.5).map { name -> String in
    return "Person Name = \(name)"
}
return Driver.just(personNameMessage)

and then in Test Case:

let scheduler = TestScheduler(initialClock: 0)
let personNameInput = scheduler.createHotObservable([next(100, "John Doe")])
let personObserver = scheduler.createObserver(String.self)
output.personNameWelcome
    .asObservable()
    .subscribe(personObserver)
    .disposed(disposeBag)

scheduler.start()

print(observer.events)

But it did not emitting the event. I've try adding scheduler.advanceBy(550) after scheduler.start() but the results are the same.

Please help.

Thank you.

Upvotes: 3

Views: 2359

Answers (3)

Abuzeid
Abuzeid

Reputation: 1022

The issue here is not in debounce method itself however, if your issue in testing the debounce method you have to change the resolution of the test scheduler to know more about scheduler resolution

But the real issue here is to test Observable works on different schedulers since debounce usually uses a different scheduler

Solution : to use SharingScheduler.make()

import RxCocoa

let personNameMessage = input.personName.debounce(0.5,scheduler: SharingScheduler.make()).map { name -> String in
    return "Person Name = \(name)"
}
return Driver.just(personNameMessage)
//The test case
func testDebounce() throws {
    let schedular = TestScheduler(initialClock: 0, resolution: 0.001)
    SharingScheduler.mock(scheduler: schedular) {
        let observer = schedular.createObserver(Double.self)
        schedular.createColdObservable([.next(0, 0)]).bind(to: observer).disposed(by: bag)
        schedular.start()

        XCTAssertEqual(oObserver.events, [.next(700, 100)])
    }
}

Upvotes: 3

Shai Mishali
Shai Mishali

Reputation: 9382

Given the fact you're using debounce without specifying a scheduler, I'm assuming personName is actually a Driver - in which case, it will use DriverSharingStrategy.scheduler as its default scheduler.

By default, that leads to MainScheduler.instance, but in a test scenario, you can simply mock using the SharingScheduler class.

SharingScheduler.mock(scheduler: yourTestScheduler) {
    /// make all your assertions here.
    /// the `mock()` will make `DriverSharingStrategy.scheduler` return
    /// your test scheduler, instead of the default one.
}

Upvotes: 5

Daniel T.
Daniel T.

Reputation: 33967

When you really think about it, you don't need to test whether the debounce works (of course it works, RxSwift has several tests that prove it works,) all you need to test is that it is part of the chain. For that, you can simply load the text of the .swift file and run a regex over it.

Upvotes: 0

Related Questions