By Navdeep Singh
RxTest
and
RxBlocking
are part of the RxSwift repository. They are made available via separate pods, however, and so require separate imports.
RxTest
provides useful additions for testing Rx code. It includes
TestScheduler
, which is a virtual time scheduler, and provides methods for adding events at precise time intervals.
RxBlocking
, on the other hand, enables you to convert a regular Observable sequence to a blocking observable, which blocks the thread it’s running on until the observable sequence completes or a specified timeout is reached. This makes testing asynchronous operations much easier.
Let’s look at each one now.
RxTest
As described above,
RxTest
is part of the same repository as
RxSwift.
There is one more thing to know about
RxTest
before we dive into some RxTesting: RxTest exposes two types of Observables for testing purposes.
HotObservables
ColdObservables
HotObservables replay events at specified times using a test scheduler, regardless of whether there are any subscribers.
ColdObservables work more like regular Observables, replaying their elements to their new subscribers upon subscription.
RxBlocking
If you are familiar with expectations in
XCTest
, you will know that it’s another way to test asynchronous operations. Using RxBlocking just happens to be way easier. Let’s start with a small implementation so we can see how to take advantage of this library while testing asynchronous operations.
Testing with RxBlocking
We will start a new test and create an Observable of 10, 20, and 30, as follows:
func testBlocking(){ let observableToTest = Observable.of(10, 20, 30) }
Now we will define the result as equal to calling toBlocking() on the observable we created:
let result = observableToTest.toBlocking()
toBlocking()
returns a blocking Observable to a straight array, as you can see here:
We will need to use the first method if we want to discover which is a throwing method. So we will wrap it in a do catch statement, and then we will add an
AssertEquals
statement if it is successful, as follows:
func testBlocking(){ let observableToTest = Observable.of(10, 20, 30) do{ let result = try observableToTest.toBlocking().first() XCTAssertEqual(result, 10) } catch { } }
Alternatively, an Assert fails if it’s not this:
do{ let result = try observableToTest.toBlocking().first() XCTAssertEqual(result, 10) } catch { XCTFail(error.localizedDescription) }
That’s it! Let’s run the test, and you will see that the test passes. We can simplify this test with just two lines of code by forcing the try.
Again, this is more acceptable on test than production code. We will comment out the do catch statement and then write the assert equals in a single line, as follows:
XCTAssertEqual(try! observableToTest.toBlocking().first(), 10)
Rerun the test, and you will see that the test passes once again. The overall code with comments looks like this:
func testBlocking(){ let observableToTest = Observable.of(10, 20, 30)
How’s that for succinct?
Truth be told, that Observable sequence would actually be synchronous already if we printed emitted elements in a subscription to it followed by a marker. The marker will be printed after the subscription’s completed event.
To test an actual asynchronous operation, we will write one more test. This time, we will use a concurrent scheduler on a background thread, as follows:
func testAsynchronousToArry(){ let scheduler = ConcurrentDispatchQueueScheduler(qos: .background) }
Now, we will create an Observable of the simple sequence of integers. We will use map to double each value, as follows:
let intObservbale = Observable.of(10, 20, 30) .map{ $0 * 2 }
Then, we will subscribe on the scheduler:
let intObservbale = Observable.of(10, 20, 30) .map{ $0 * 2 } .subscribeOn(scheduler)
Now we will write a do catch statement that is similar to the last test and calls toBlocking on the Observable, which should be observed on the main scheduler, as follows:
do{ let result = try intObservbale.observeOn(MainScheduler.instance).toBlocking().toArray() } catch { }
Then, we will add the same assertions as the previous example:
do{ let result = try intObservbale.observeOn(MainScheduler.instance).toBlocking().toArray() XCTAssertEqual(result, [20, 40, 60]) } catch { XCTFail(error.localizedDescription) }
Now we will run the test, and you will note that it passes with the green check mark in the gutter.
Note that the marker is printed before the emitted elements in the console, as shown:
This is because these operations were executed asynchronously.
For other updates you can follow me on Twitter on my twitter handle @NavRudraSambyal
To work with examples of hot and cold observables, you can find the link to my book
Reactive programming in Swift 4
Thanks for reading, please share it if you found it useful :)
freeCodeCamp is a donor-supported tax-exempt 501(c)(3) charity organization (United States Federal Tax Identification Number: 82-0779546)
Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles, and interactive coding lessons - all freely available to the public.
Donations to freeCodeCamp go toward our education initiatives, and help pay for servers, services, and staff.
You can
make a tax-deductible donation here
.
Learn CSS Transform
Build a Static Blog
Build an AI Chatbot
What is Programming?
Python Code Examples
Open Source for Devs
HTTP Networking in JS
Write React Unit Tests
Learn Algorithms in JS
How to Write Clean Code
Learn PHP
Learn Java
Learn Swift
Learn Golang
Learn Node.js
Learn CSS Grid
Learn Solidity
Learn Express.js
Learn JS Modules
Learn Apache Kafka
REST API Best Practices
Front-End JS Development
Learn to Build REST APIs
Intermediate TS and React
Command Line for Beginners
Intro to Operating Systems
Learn to Build GraphQL APIs
OSS Security Best Practices
Distributed Systems Patterns
Software Architecture Patterns