Testing with RxBlocking, part 1

Whenever you decide to test your Rx code you have not one but two excellent choices - RxTest and RxBlocking.

In this blog post I’ll go over the RxBlocking API and explain shortly how does the libary work. In Part 2 I’ll go over a bunch of real-life examples from open source I’ve written.

Testing with RxTest

pod RxTest to install it to your test suite from https://github.com/ReactiveX/RxSwift/tree/master/RxTest

I’ve already written in the past about RxTest and few people have thanked me personally for shading some light on its usage, so if you’re interested head to the original article and read through: Testing your RxSwift code, part1.

RxTest is excellent for the cases when you need to provide a bunch of inputs and record and inspect some outputs. For example you have a view model, which given a city name outputs the name of the country the city is located in. RxTest makes it easy to test the sequence "Berlin", "London", "Barcelona" as input and compare if the recorded output was ["Germany", "UK", "Spain"] in one pass. Simple!

Testing with RxBlocking

pod RxBlocking to install it to your test suite from https://github.com/ReactiveX/RxSwift/tree/master/RxBlocking

RxBlocking on the other hand is reaaaaaly handy in case you need to test some asynchronous functionality where you can’t control the source of asynchronisity. Often times this means you’re stepping up from unit tests to integration tests but nonetheless you do need a tool write those too.

What RxBlocking is great to is to allow you to consume an observable sequence in batches or even wait on a single element to be emitted. It simplifies great async tests and this is what I’m gonna write about in this and the next blog posts.

RxBlocking crash course

The RxBlocking library is very very simple and it features only a handful of operators. Let’s look at couple of examples and after that we’re going to dive into more elaborated examples.

What does RxBlocking do?

RxBlocking allows you to “stop and wait for a given condition to be fulfilled”. In regards to testing observable sequences a handy “condition” is to wait for an element to be emitted. Let’s have a look:

let element = try! items.toBlocking().first()!
XCTAssertEqual(1, element)

What this code does is the following

  1. items is an Observable<Int>, which you want to test
  2. items.toBlocking() converts it to a blocking observable, and when you call first() on it the runtime “stops” and waits for the next element to be emitted.
  3. “waiting” for an element does not block the current thread but it uses the runloop to periodically check if the condition has been fulfilled
  4. finally, when items emits an element, the result is assigned to element
  5. then the execution continues to the next line and by using XCTAssertEqual() we can check if element contains the value we expect.

This is a minimal explanation of RxBlocking and a full unit test. The big win of using toBlocking() for that test is that the code is asynchronous - it could, for example, take few seconds before items emits.

You can of course write the same test as an asynchronous XCTest test, but hey look at how clear and neat the RxBlocking code looks!

Let’s look at few quick examples.

Waiting on completing sequences

In case the observable sequence completes, you can get all the emitted elements by using toArray() like so:

let elements = try! items.toBlocking().toArray()
XCTAssertEqual([1, 5, 10, 15], elements)

toArray() waits until the sequence completes and returns all emitted elements as an array. On the next line you can compare the result elements to the values you expected.

Waiting on non-completing sequences

toArray() can be used directly on any observable sequence, which completes (e.g. the .completed event is the “condition” to un-block). But how about if your sequence does not complete and you’d like to check the 4th and 5th elements only?

You can use all operators as usual on your sequence before you convert it to a blocking observable. Let’s have a look:

let elements = try! items.skip(3).take(2).toBlocking().toArray()
XCTAssertEqual([15, 20], elements)

In this case you will skip over the first 3 elements and take only the next 2 in your sequence. Then you use toBlocking() and get the resulting 2 elements by using toArray(). Bam!

Waiting for a given time only

It’s worth mentioning that in case you don’t want your test to wait for ever (which is mostly the case?) you can provide a timeout parameter:

let elements = try! items.toBlocking(timeout: 1).toArray()

If items does not complete within 1 second toArray() will raise an error. If you want to handle this properly use try? instead of try! or catch the thrown error otherwise.

Waiting on the final element of a sequence

Finally, you might be interested only in the final element of a squence. This is handy if the elements in the sequence represent some kind of state and you want to test only the final state of the observable.

let lastElement = try! items.toBlocking().last()!
XCTAssertEqual(1, lastElement)

last() will “stop and wait” for the observable to complete and return as result the last element of the sequence.

Where to go from here?

In Part 2 I’ll look over a number of real-life examples to give you a better idea where you can take your tests with the power of RxBlocking.

To learn more about RxSwift and testing check out the RxBook! The book is available at http://raywenderlich.com/store - this is where you can see all updates, discuss in the website forums, etc.

Hope that post was helpful, and if you want to get in touch you can find me here

Share this post:

If you'd like to learn how to create professional production apps with RxSwift, the best resource out there is the RxSwift book written by Florent Pillet, Junior Bontognali, Marin Todorov, & Scott Gardner.

It features 20+ chapters covering the basics, the Rx operators, and advanced topics like testing, error handling, and app architecture.

Available from Ray Wenderlich: » Learn more.