Testing in RxTest with ColdObservables

To show an example of working with a ColdObservable in RxTest, we will duplicate the previous example and change the name.

A ColdObservable in RxTest will only emit when there is a subscriber, and it will emit all its events to each subscriber on subscription. We will create two subscriptions in this example, so rather than using the subscription's dispose() property, we will use disposeBag this time. We will need two observers for this example, so we will duplicate the single one and then rename them as follows:

let disposeBag = DisposeBag()
let firstObserver = scheduler.createObserver(Int.self)
let secondObserver = scheduler.createObserver(Int.self)

Also, we will need two map Observables to test that each one gets all three events, so we will duplicate the original one, rename them, and change the operation so that we can distinguish them later. We will change the second one to multiply by four instead of two, as follows:

 let firstObservableForMap = observableSeq.map {$0 * 2}
let secondObservableForMap = observableSeq.map {$0 * 4}

We will subscribe to the first Observable at time zero and add it to the disposeBag instead of assigning it to the subscription property; then we will duplicate that to subscribe to the second observable at time 150. As we used a cold observable, it should not matter when we scheduled subscription. Each subscriber should receive all the events. That's the basis of this test. We will leave the line that starts the scheduler as-is, and then we will modify the results definition to first store the first observer's events, assign the result to a variable so that we can modify it later, and then append that array with the second observer's events. Finally, we will change the assertion for the new expected results, that is, that the second map operation's results will be the original observable's values times three, appending on to the first map operator's results that are the same as earlier. Let's change the assertion to match the expected result, as follows:

func testMapOperatorCold(){
let disposeBag = DisposeBag()

let firstObserver = scheduler.createObserver(Int.self)
let secondObserver = scheduler.createObserver(Int.self)

let observableSeq = scheduler.createColdObservable([
next(100,10),
next(200,20),
next(300,30)
])

let firstObservableForMap = observableSeq.map {$0 * 2}
let secondObservableForMap = observableSeq.map {$0 * 4}
scheduler.scheduleAt(0){
firstObservableForMap.subscribe(firstObserver).disposed(by:
disposeBag)
}
scheduler.scheduleAt(150){

secondObservableForMap.subscribe(secondObserver).disposed(by:
disposeBag)
}
scheduler.start()

var restultsFromMapOperation = firstObserver.events.map{
$0.value.element!
}

_ = secondObserver.events.map{
restultsFromMapOperation.append($0.value.element!)
}

XCTAssertEqual(restultsFromMapOperation, [20, 40, 60, 40, 80, 120])
}

Finally, let's run the test, and you will see that the diamond next to the function name in the gutter turns green with a check mark.

Let's add a testMapHot test that follows the same logic as testMapCold, except that it uses a HotObservable. You can try to implement it on your own, before going on to read the implementation and match your implementation later.

Okay, let's proceed with the implementation. The solution is very simple—we just need to replace createColdObservable with createHotObservable, as follows:

func testMapOperatorHot(){
let disposeBag = DisposeBag()

let firstObserver = scheduler.createObserver(Int.self)
let secondObserver = scheduler.createObserver(Int.self)

let observableSeq = scheduler.createHotObservable([
next(100,10),
next(200,20),
next(300,30)
])

let firstObservableForMap = observableSeq.map {$0 * 2}
let secondObservableForMap = observableSeq.map {$0 * 4}
scheduler.scheduleAt(0){
firstObservableForMap.subscribe(firstObserver).disposed(by:
disposeBag)
}
scheduler.scheduleAt(150){
secondObservableForMap.subscribe(secondObserver).disposed(by:
disposeBag)
}
scheduler.start()

var restultsFromMapOperation = firstObserver.events.map{
$0.value.element!
}

_ = secondObserver.events.map{
restultsFromMapOperation.append($0.value.element!)
}

XCTAssertEqual(restultsFromMapOperation, [20, 40, 60, 80, 120])
}

Since we used a HotObservable, this time the second observer will not get the first event at 100, because it didn't subscribe until after it was emitted at 150. So the expected results are [20, 40, 60, 80, 120].

Run the test once again with the expected output in the assert, and you will see the test pass.

In the next section, we will take a look at RxBlocking, which essentially turns an asynchronous operation into a synchronous one in order to test it more easily.