Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we'll compare two popular ways of creating a Single object in RxJava, and we'll test the implementations using a TestSubscriber. First, we'll look at the Single.just() factory method and use it eagerly to create an instance of the object. After that, we'll learn about Single.fromCallable() and see how to use it to improve performance.

2. Single.just()

Single.just() is the straightforward way of creating an instance of an Observable. It takes an object as an argument and wraps it inside RxJava's Single:

Single<String> employee = Single.just("John Doe");

Most of the time, though, we'll retrieve or compute this data somehow. For demonstration purposes, let's pretend we're retrieving the employee's name from the EmployeeRepository class. For testing, we'll use Mockito to check the interactions with this repository and TestSubscriber to test the value published by the resulting observable:

@Test
void givenASubscriber_whenUsingJust_thenReturnTheCorrectValue() {
    TestSubscriber<String> testSubscriber = new TestSubscriber<>();
    Mockito.when(repository.findById(123L)).thenReturn("John Doe");

    Single<String> employee = Single.just(repository.findById(123L));
    employee.subscribe(testSubscriber);

    testSubscriber.assertValue("John Doe");
    testSubscriber.assertCompleted();
}

As expected, the testSubscriber is publishing the same value as the one returned by the repository. On the other hand, even if there are no subscribers, the data will still be fetched. Let's use Mockito to verify the number of interactions with the EmployeeRepostory:

@Test
void givenNoSubscriber_whenUsingJust_thenDataIsFetched() {
    Mockito.when(repository.findById(123L)).thenReturn("John Doe");

    Single<String> employee = Single.just(repository.findById(123L));

    Mockito.verify(repository, times(1)).findById(123L);
}

3. Single.fromCallable()

As an alternative, we can use Single.fromCallable(). In this case, we need to provide an implementation of the Callable interface or a lambda expression. In other words, we can pass a function that will fetch the data, and this function will only be called when somebody subscribes. Therefore, if there are no subscribers, there will be no interaction with the repository:

@Test
void givenNoSubscriber_whenUsingFromCallable_thenNoDataIsFetched() {
    Single<String> employee = Single.fromCallable(() -> repository.findById(123L));

    Mockito.verify(repository, never()).findById(123L);
}

But, as soon as somebody subscribes to the employee, the data will be fetched and then published. Let's add another test and check if the resulting Single object publishes the correct value:

@Test
void givenASubscriber_whenUsingFromCallable_thenReturnCorrectValue() {
    TestSubscriber<String> testSubscriber = new TestSubscriber<>();
    Mockito.when(repository.findById(123L)).thenReturn("John Doe");

    Single<String> employee = Single.fromCallable(() -> repository.findById(123L));
    employee.subscribe(testSubscriber);

    Mockito.verify(repository, times(1)).findById(123L);
    testSubscriber.assertCompleted();
    testSubscriber.assertValue("John Doe");
}

4. Conclusion

In this article, we compared Single‘s just() and fromCallable() factory methods. We learned that if we want to take advantage of the lazy evaluation when fetching the data, we should use the fromCallable() option.

The full source code for the project, including all the code samples used here, can be found over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
Comments are closed on this article!