Chapter 7. Testing Your RxJava Application

While writing software, especially software which will be used by a lot of users, we need to be sure that everything is working correctly. We can write readable, well-structured, and modular code, which will make it easier for changing and maintaining. We should write tests because, with every feature, there is the danger of regression. When we already have tests for the existing code, refactoring it won't be as hard, because the tests could be run against the new, changed code.

Almost everything needs to be tested and automated. There are even ideologies such as test-driven development (TDD) and behavior-driven development (BDD). If we don't write automated tests, our ever-changing code tends to break over time and becomes even harder to test and maintain.

In this chapter, we won't be talking about why we need to test our code. We'll accept that this is mandatory and is part of our life as programmers. We'll learn how to test the code written using RxJava.

We will see that it is not so hard to write unit tests for it, but that there are some hard-to-test cases, such as asynchronous Observable instances, for example. We will learn about some new operators, which will help us in testing and a new kind of Observable instance.

With that said, here is what we will cover in this chapter:

  • Testing Observable instances via the BlockingObservable class and aggregating operators
  • Using the TestSubscriber instance for in-depth testing
  • The TestScheduler class and testing asynchronous Observable instances

Testing using simple subscription

We can test what we get by simply subscribing to the source Observable instance and collecting all of the incoming notifications. In order to demonstrate that, we'll develop a factory method for creating a new Observable instance and will test its behavior.

The method will receive a Comparator instance and multiple items, and will return Observable instance, emitting these items as a sorted sequence. The items will be sorted according to the Comparator instance passed.

We can develop the method using TDD. Let's first define the test as follows:

public class SortedObservableTest {
  private Observable<String> tested;
  private List<String> expected;
  @Before
  public void before() {
    tested = CreateObservable.<String>sorted(
      (a, b) -> a.compareTo(b),
      "Star", "Bar", "Car", "War", "Far", "Jar");
    expected = Arrays.asList(
      "Bar", "Car", "Far", "Jar", "Star", "War"
    );
  }
  TestData data = new TestData();
  tested.subscribe(
    (v) -> data.getResult().add(v),
    (e) -> data.setError(e),
    () -> data.setCompleted(true)
  );
  Assert.assertTrue(data.isCompleted());
  Assert.assertNull(data.getError());
  Assert.assertEquals(expected, data.getResult());
}

Note

The examples of this chapter use the JUnit framework for testing. You can find out more about this at http://junit.org.

The test uses two variables to store the predefined reusable state. The first one is the Observable instance we use as source—tested. In the setup @Before method, it is assigned to the result of our method CreateObservable.sorted(Comparator, T...), which is not implemented yet. We compare a set of String instances and expect them to be received in the order they are stored in the expected variable—the second reusable field.

The test itself is quite verbose. It uses an instance of the TestData class to store the notifications incoming from the tested Observable instances.

If there is an OnCompleted notification, the data.completed field is set to True. We expect this to happen, and that's why we assert it at the end of the test method. If there is an OnError notification, the data.error field is set to the error. We don't expect that to happen, so we assert it to be null.

Every incoming item emitted by the Observable instances is added to the data.resultList field. At the end, it should be equal to the expected List variable, and we assert that.

Note

The source code for the preceding test can be viewed/downloaded at https://github.com/meddle0x53/learning-rxjava/blob/master/src/test/java/com/packtpub/reactive/chapter07/SortedObservableTest.java—this is the first test method.

However, this test fails, of course, because the CreateObservable.sorted(Comparator, T...) method is not implemented yet. Let's implement it and run the test again:

@SafeVarargs
public static <T> Observable<T> sorted(
  Comparator<? super T> comparator,
  T... data) {
    List<T> listData = Arrays.asList(data);
    listData.sort(comparator);
  return Observable.from(listData);
}

It's that simple! It just turns the passed varargs array into a List variable and uses its sort() method to sort it with the passed Comparator instance. Then, using the Observable.from(Iterable) method, we return the desired Observable instance.

If we run the test now, it will pass. This is good! We've got our first test! But writing tests similar to this requires a lot of boilerplate code. We always need these three state variables and we always need to assert the same things. And what about asynchronous Observable instances, such as the ones created by interval() and timer() methods?

There are some techniques for removing the boilerplate variables, and later, we'll look at how to test asynchronous behavior as well. For now, we'll introduce one new type of observable.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.176.80