Testing Your RxSwift Code | raywenderlich.com

Writing reactive apps with RxSwift is a conceptually different task to writing applications “the regular way.” Things in your app usually won’t have a singular value, but are, instead, represented as a stream of values over time. Learn the key to testing RxSwift code in this tutorial. Testing streams of values is not as trivial as simply asserting a single value. But worry not, this tutorial on testing RxSwift code will get you up to speed on your way to becoming an expert!

This is a companion discussion topic for the original entry at https://www.raywenderlich.com/7408-testing-your-rxswift-code
1 Like

Very nice article!

I found that “LaunchScreen.storyboard” is missing contained in “final” project.
The file seems to refer to your local file.


Hey @mono0926 - Thank you so much for the kind compliment and for reporting :slight_smile:
This should be fixed now. Let me know if there are any other issues.


1 Like

Love the tutorial!

And I have the question. If a viewModel contains Drivers shouldn’t we init it like that?

override func setUp() {
    scheduler = TestScheduler(initialClock: 0)
    disposeBag = DisposeBag()
    SharingScheduler.mock(scheduler: scheduler) {
        viewModel = MetronomeViewModel()

I have read about it over here: RxTest - How to test the Observable in Swift - Code in a suit
(before it was driveOnScheduler(testScheduler) but now it’s deprecated)

Hey there! Excellent question.
I want to start off with the fact that, we unfortunately as authors can’t cover 100% of the information in a single tutorial, but this is a great piece to talk about, so let me expand a bit, and sorry in advance for the lengthy explanation but it’s great information to know :slight_smile:

Basically, if our ViewModel wouldn’t do anything that works with any specific scheduler (meaning time-based operations: timer, interval, retry, etc.) - you usually won’t even need to inject a scheduler, but in the Metronome’s case you’ll notice we’re injecting the scheduler since we’re using Observable.interval to calculate our “beats”.

OK, great, so far so good.

Now, what happens if instead of Observable.interval(_:scheduler:), you would use Driver.interval(_:) ?
Drivers don’t accept a Scheduler, since they always execute on MainScheduler.instance.

So, actually that’s not entirely true. Driver is a SharingStrategy, and you’ll see it’s getting its scheduler from something called SharingScheduler.make().

So, what is this SharingScheduler.make() ? By default, it just returns MainScheduler.instance, which is why all Driver schedule events on that scheduler by default. So, since we can’t inject it, how can we “mock” that SharingScheduler’s scheduler?

That’s exactly what SharingScheduler.mock is for!

When you use SharingScheduler.mock(scheduler: testScheduler) { ... commands ... } - what you’re saying is, whenever you would use a Sharing Strategy, instead of using the default scheduler, use my injected scheduler. So in a way, it’s the same as injecting your scheduler into your View Model, but across all SharingStrategies (Driver/Signal) in the scope of that call.

Sorry if that was a bit technical, hope it helps / made sense to you!


Thanks for elaborating on SharingScheduler.mock! Does that also mean the way @destroplayer is using the mock is the right way (setting it up in the setUp method)? Or would you suggest another way, for example wrapping your whole test in the mock?

Hey! I think it’s a matter of preference but my instinct and personal preference is to wrap individual tests with SharingScheduler.mock, where they’re needed, and not wrap the entire “view model”

That makes sense. And why is it that you don’t need to use SharingScheduler.mock in your tests in Raytronome? You are using drivers as the output for your ViewModel as right?

Is that because although you are using drivers, the events originate from the testScheduler?

It is the same reason that you don’t necessarily need to inject a scheduler in non-SharingStrategy cases. For many “Immediately Scheduled” thiings in your view model, tests would “just work” usually.

As soon as you use time-based operators (or those that take a scheduler) like delay, retry, throttle, debounce, etc — you’ll want to mock the scheduler. In general it would be a best bet to just always mock the scheduler and be done with it.

Check. Thanks for answering my questions 1y after the tutorial! :blush:

Happy to :slight_smile: Thanks for your kind words.

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!