While catching up with the latest Android novelties I could not ignore RxJava, which seems to grow in popularity between android developers.
If you just heard about it, and you want to get your feet wet, I really recommend Dan Lew’s Grokking with RxJava series as a starting point.
RxJava is asynchronous by nature, so unit testing it might seem a daunting at first, especially if you use that asynchronous interaction to test stuff. Luckily, RxJava (and RxAndroid) come with a couple of tools that will make our life a lot easier.
What to (unit) test
There are at least a couple of things you’ll want to test:
- You will want to test the observables, meaning not only the observables you built, but also the resulting composition of the various operators you may want to apply to them.
- Given a certain observable (or its mock), you will want to test how the rest of your application behaves while triggered by the subscription.
Testing the observables
Despite the fact that a subscription is asynchronous, there are (at least) a couple of ways to make the stream of your observable synchronous.
The first way is by using
This works because toBlocking converts the observable to a blocking one, while first returns the first emitted element. The calling code will wait synchronously until the observer calls onCompleted().
The official way to test an observable is by using a TestSubscriber, an helper subscriber provided directly by the RxJava library. As with toBlocking, a test subscription is synchronous. Here you can find an example:
1 2 3 4 5 6 7
TestSubscriber comes with a bunch of helper methods for testing, like specific assertions and other stuff. On top of that, its
getOnNextEvents() method is blocking and will return all the emitted items as elements of a list.
This is a neat way to test not only your observers, but also to check if the compositions you put in place are working as expected. That makes testing observables super easy.
Testing the subscription
Once your observables are in place, you will likely to be observing them on some thread, and subscribing them on some other thread. This will make it harder for us to test how our activity (or fragment) reacts to a triggered subscription.
RxJava (and RxAndroid) provide a way to override the schedulers exposed when
AndroidSchedulers.mainThread() are called. By replacing them with
Schedulers.immediate(), your code will run immediately and you’ll be able to see its results.
The solution is a bit hacky, since we need to call
reset() method before overriding RxJava’s schedulers, which is package protected. I took inspiration from Alexis Mas' blogpost extending RxJavaPlugins class (there no need for that with RxAndroid):
1 2 3 4 5 6 7 8 9 10 11
Registering a scheduler hook that provides a custom implemetation (Schedulers.immediate()) will end up in overriding the schedulers we are using.
As pointed out by Patrik Åkerfeldt in the comments, since the hooks are asked to provide a scheduler implementation during the initialization of the Schedulers class, we have only one chance to override the default schedulers. For this reason, there is no point in setting them up in the
setup phases of all our tests.
The best place to override them once seems to be the
TestRunner will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13
And this is how the
teardown() methods will look like (here I am using robolectric but it makes no difference with AndroidTests):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
As I already mentioned, you can inject the custom schedulers only once per test session. On the other hand, RxAndroidPlugins come with a reset method that will allow us to hook in different schedulers in different threads.
This, together with a non blocking observable (for instance by replacing your long taking observable with a mocked
Observable.just()) will make our test synchronous.
In order to inject a mocked observable, we can override the Application object used by Robolectric, as described in my previous post here .
Bonus point: debugging
If the unit tests are not enough, and you want to check what is happening inside the chaining / transformation of the stream, you can set an
ObservableExecutionHook that will be triggered when observables are being called:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
- Use TestSubscriber when testing how an observable (or a composition of observables) behaves
- Mock your observable and override the default schedulers to test how the subscribing class works
- Enable the tracking of your observables by registering an observable execution hook
A working example (rubber chickens included) can be found on my github repo.
- Unit testing rxjava (observables) by Iván Carballo
- Unit testing rxjava (subscription) by Alexis Mas
- This and this episodes of Fragmented Podcast where Dan Lew gave some insights about RxJava, where I heard about the scheduler overriding trick
- Patrik Åkerfeldt’s example that demonstrates how the scheduler injection works only before Scheduler class initialization