Unit Testing: How to verify and mock onCompleted for an Observable in RxJava within Android

12,606

Solution 1

Instead of mocking the Subscriber, you should create a TestSubscriber for RxJava 1:

when(myAPI.Complete(anyString(), any(MyContainer.class)))
        .thenReturn(Observable.<GenericResponse>error(new Throwable("An error has occurred!")));

TestSubscriber genericResponseSubscriber = TestSubscriber.create();

myPresenter.myUseCase(id, container, genericResponseSubscriber);

// To check for an error
genericResponseSubscriber.assertError(Throwable.class)

// To check for completion
genericResponseSubscriber.assertCompleted()

You might need to be a bit more specific about which error class you expect. Check out the TestSubscriber documention. There is tons of more stuff you can verify with this class.

Happy testing!

Solution 2

You should use the class TestObserver for testing the Observable, in this way:

public Observable<Integer> getObservable() {
     return Observable.just(12, 20, 330);
}

@Test
public void testObservable() {
     Observable<Integer> obs = getObservable();
     TestObserver<Integer> testObserver = TestObserver.create();
     obs.subscribe(testObserver);

     testObserver.assertComplete();
     testObserver.assertResult(12, 20, 330);
 }

In this way you can verify that it completes and emits all the expected items.

If you want to create a mocked version of your observable, you can just create a new Observable that has the behaviour that you want. For example:

public Observable<Integer> mockedObservableCompleteWithResult() {
        return Observable.create(e -> {
            e.onNext(12);
            e.onNext(20);
            e.onNext(330);
            e.onComplete();
        });
    }

that can be verified with the above-mentioned test.

Then we can create other mock for modelling other results

public Observable<Integer> mockedObservableError() {
            return Observable.create(e -> {
                e.onNext(12);
                e.onError(new Throwable("Generic exception"));
            });
        }

That can be verified:

@Test
public void testObservable() throws Exception {
       Observable<Integer> obs = mockedObservableError();
       TestObserver<Integer> testObserver = TestObserver.create();
       obs.subscribe(testObserver);

       testObserver.assertError(Throwable.class);
}
Share:
12,606
greysqrl
Author by

greysqrl

Updated on June 27, 2022

Comments

  • greysqrl
    greysqrl almost 2 years

    I am trying to write some unit tests for an Android application that is using Retrofit 2, Mockito 1.10 and RXJava 1.0. I am not using a java version that supports lambdas!

    My code uses Observables and I can do the following:

    when(myAPI.Complete(anyString(), any(MyContainer.class)))
            .thenReturn(Observable.<GenericResponse>error(new Throwable("An error has occurred!")));
    
    Subscriber genericResponseSubscriber = mock(Subscriber.class);
    
    myPresenter.myUseCase(id, container, genericResponseSubscriber);
    
    verify(genericResponseSubscriber, times(1)).onError(any(Throwable.class));
    

    The above code works fine and allows me to throw an error and capture it within the test.

    What I need to be able to do as well (of course) :) is to capture positive conditions. I feel like it's obvious but can't find the answer I need.

    How can I capture onComplete and onNext cases ?

    I know that the verification for onComplete would be...

    verify(genericResponseSubscriber, times(1)).onCompleted();

    But I can't see what my 'when' clause should be. I tried the following but that fails:

    GenericResponse response = new GenericResponse();
    response.setSuccess(true);
    
    when(myAPI.orderComplete(anyString(), any(MyContainer.class)))
            .thenReturn(Observable.just(response));
    
    Subscriber genericResponseSubscriber = mock(Subscriber.class);
    
    myPresenter.myUseCase(id, container, genericResponseSubscriber);
    
    verify(genericResponseSubscriber, times(1)).onCompleted();
    

    The failure here is that subscriber.onStart() was instead called.

    So, what I would like to know is, how I can mock and verify the 'onComplete' and 'onNext' calls, please and more importantly what I should have looked to be able to have resolved this myself rather than having to ask! :)

    As always, any help is appreciated.

    Edit..

    My onError working test case..

        public void UseCaseOnError() throws Exception {
        
         String id = "5";
    
        
         order Order = new Order();
        
         SomeContainer myContainer = new SomeContainer(order);
    
        
    
         when(myRetroFitAPI.complete(anyString(), any(SomeContainer.class)))
    

    .thenReturn(Observable.error(new Throwable(“My error!")));
 


         Subscriber genericResponseSubscriber = mock(Subscriber.class);
    
        
    
         orderPresenter.doUseCase(id, myContainer, genericResponseSubscriber);
    
        
    
         verify(genericResponseSubscriber,times(1)).onError(any(Throwable.class));
    
    
    
    }
    

    What I should really add is that, I feel there should be an equivalent for onError in terms of a positive state, i.e. onCompleted. If I do the same but with onCompleted instead, my verification fails as it detects onStart has been called instead which I am finding rather confusing.

    I have tried using the ReplaySubject as such:

    public void createOrderOnCompleteError() {
        orderOnCompleteSubject.onError(new Throwable("I am an error"));
    }
    
    public void createOrderOnCompleteSuccess() {
        orderOnCompleteSubject.onNext(new GenericResponse().setSuccess(true));
        orderOnCompleteSubject.onCompleted();
    }
    

    The error mechanism works fine.. the completed mechanism does not...