添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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

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.

Shai.

Love the tutorial!

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

override func setUp() {
    super.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!
Shai.

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.