'Unit Testing RxJava doOnSubscribe and doFinally

How do I create a unit test that a certain side effect is done on doOnScubscribe and doFinally of an rxjava chain?

For Example:

Observable.requestSomeValueFromWeb()
            .doOnSubscribe(() -> showLoading = true)
            .doFinally(() -> showLoading = false)
            .subscribe(result -> doSomething(result), error -> doErrorHandling(error));

How do I test in the scenario above that the showLoading was set to true on subscribe and false when the observable was disposed?

TestSubscriber<WebServiceResponse> loginRequestSubscriber = new TestSubscriber<>();

clientLoginViewModel.requestLogin().subscribe(loginRequestSubscriber);

// check that showLoading was true when webservice was called
assertEquals(true, showLoading);

// check that showLoading was false when webservice was finished
assertEquals(false, showLoading);

loginRequestSubscriber.assertSubscribed();


Solution 1:[1]

If I understand correctly, your Object Under Test is the ClientLoginViewModel, so I'm trying to work from there. Let me know if I'm mistaken and I can revisit my answer:

The classes from your system:

interface WebServiceResponse { } // We don't care about this here

interface Network {
    // This is whatever interacts with the Network, and we'll mock it out
    Single<WebServiceResponse> requestSomeValue();
}

// The class we are testing
class ClientLoginViewModel {

    final Network mNetwork;

    // This is the field we want to check... you probably want to make it
    // private and have accessors for it
    boolean showLoading;

    // This allows dependency injection, so we can mock :)
    ClientLoginViewModel(final Network network) {
        mNetwork = network;
    }

    // The actual method to test!
    Single<WebServiceResponse> requestLogin() {
       return mNetwork.requestSomeValue()
           .doOnSubscribe(disposable -> showLoading = true)
           .doFinally(() -> showLoading = false);
    }
}

And now the test!!!

class ClientLoginViewModelTest {

    @Test
    public void testLoading() {
        final Network network = mock(Network.class);
        final WebServiceResponse response = mock(WebServiceResponse.class);

        // This is the trick! We'll use it to allow us to assert anything
        // before the stream is done
        final PublishSubject<Boolean> delayer = PublishSubject.create();
        when(network.requestSomeValue())
            .thenReturn(
               
 Single.just(response).delaySubscription(publishSubject)
            );

        final ClientLoginViewModel clientLoginViewModel = new ClientLoginViewModel(network);

        clientLoginViewModel
            .requestLogin()
            .test();

        // check that showLoading was true when webservice was called
        assertEquals(true, clientLoginViewModel.showLoading);

        // now let the response from the Network continue
        publishSubject.onComplete();

        // check that showLoading was false when webservice was finished
        assertEquals(false, clientLoginViewModel.showLoading);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1