Visually test your async code with marble testing: Rx (Java/JS)


The quickie of Alexandre Delattre (Viseo) on Marble testing with Rx (JS/Java/…) during the DevFest Toulouse 2017 was particularly interesting.

What is Rx?

Rx is a library for composing asynchronous and event-based programs by using observable sequences. It provides one core type, the Observable, satellite types (Observer, Schedulers, Subjects) and operators inspired by Array#extras (map, filter, reduce, every, etc) to allow handling asynchronous events as collections.

From RxJS doc

We can use Rx in the frontend (for service calls combinations and reactive user interface) as well as in the backend (micro-services calls combinations, websockets, …).


The current trend is to transform imperative programming into reactive functional programming. With the tools at our disposal, testing asynchronous behaviours is hard, and often, developers just skip this important step. But it is possible! And now, simpler than ever. So how to do that? How to check that our streams unfold the way we want them to?

You guessed right: with Marble Testing.

Marble diagrams

In order to representObservables, we define Marble diagrams. They are drawn as a horizontal timeline, with events occurring as visual nodes. We can represent them like this example of a the merge function that takes two observables and return a merge of the two.

Marble diagrams

You can refer to RxMarbles website in order to find interactive diagrams of Rx Observables. In order to use them in code, we define an ASCII notation.

First, we define the time frame (default is 10ms). Then we can have a look at the different symbols that we need:

-  : Nothing happens during one frame
|  : the observable is completed (onComplete)
#  : observable error (onError)
x  : the observable emits a value (onNext)
^  : subscription point of an Observable (only for hot Observables)
() : value grouping

Example of a mobile weather application

For this example of application, the speaker chose the language Kotlin, but we could do the same with any Rx supported language and platform (see full list on ReactiveX site).

Application requirements

We have an “instant search” application, with the user inputting their city’s name. After a 500ms delay, we launch the search, and a loading progress is visible to the user during the search. Then the result is displayed, or an error, if need be.


Our available interfaces are the following:

interface WeatherViewModel {
    // Inputs
    val city: Subject 
    // Outputs
    val state: Observable<State>
    val weather: Observable<WeatherData>
sealed class State
object Idle : State()
object Loading : State()
data class Error(val e:Throwable) : State()
data class WeatherData (
    val city: String,
    val pictoUrl: String,
    val minTemperature: Float,
    val maxTemperature: Float


interface WeatherService {
    fun getWeather(city: String): Single<WeatherData>

city = BehaviorSubject.createDefault("")
state = BehaviorSubject.createDefault(Idle)
weather = city
    .filter { it.isNotEmpty() }
    .debounce(500, TimeUnit.MILLISECONDS, mainScheduler)
    .switchMap {
           .doOnSubscribe { state.onNext(Loading) } 
           .doOnSuccess { state.onNext(Idle) } 
           .doOnError { state.onNext(Error(it)) } 
Use case diagram

For example, in this diagram, the user starts typing “Toulouse”, and after 500ms without activity (no keystroke pressed), we call the webservice to get the weather in Toulouse. The webservice then returns the response (sunny weather). Afterwards, the user wants to check the weather in Paris, so after the delay, the webservice is called, and then we get the response.

Use case diagram

Marble testing implementation
fun setup() {
    weatherService = Mockito.mock(
    scheduler = MarbleScheduler(100)
    viewModel = WeatherViewModelImpl(weatherService, scheduler)

Following are the values that we need in order to test. We map the symbol “0” to the event “empty string”, the symbol “1” to the event the user inputs “tou”, the symbol “t” to the event the user inputs “toulouse”, etc.

val cityValues = mapOf( 
    "0" to "", 
    "1" to "tou",
    "t" to "toulouse",
    "b" to "bordeaux" 
val stateValues = mapOf(
    "i" to Idle,
    "l" to Loading,
    "e" to Error(weatherError)
val weatherValues = mapOf(
    "t" to weatherData,
    "b" to bordeauxData

And these are the data that the webservice is mocked to respond.

val weatherData = WeatherData("toulouse", "sunny", 20f, 30f) 
val bordeauxData = WeatherData("bordeaux", "cloudy", 10f, 15f) 

So now, the test look like this.

@Test fun test2Cities() {
    val s = scheduler
    val cityInput =                      "0-1-t------------b----------", cityValues) 
    // debouncing                                    -----t       -----b
            .thenReturn(s.single(                        "--t", weatherValues))
            .thenReturn(s.single(                                     "--b", weatherValues))
    s.expectObservable( "-----------t------------b---", weatherValues)
    s.expectObservable(viewModel.state).toBe(   "i--------l-i----------l-i---", stateValues)

We obtain an ASCII visual representation of what we simulate the user interaction to be, and then, we tell the test what chain of events we expect to receive from the various observables. In this representation, we can visually check how the different timelines correspond, and easily test that the more complex chains of events actually lead to the observable that we want.


Pros Cons

●      Tests are more concise and expressive

●      Complex cases can be tested visually

●      Now testing the global coherence and behaviour is made possible



●      The API suffers from differences between the different platforms

●      Alignment of marbles can be visually challenging in ASCII

Possible improvements in the future

The speaker concluded by proposing improvements in the future in order to counter the cons:

  • Uniformisation of the APIs
  • Development of a graphical editor for marbles

He added that if someone in the conference wanted to get involved and develop a graphical editor, it would be great and useful.

Jessica HORNIK
Jessica HORNIK


Leave a Reply

Your email address will not be published. Required fields are marked *