greysqrl
greysqrl

Reputation: 977

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

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...

Upvotes: 4

Views: 16453

Answers (3)

Nishant Shah
Nishant Shah

Reputation: 2092

The easy way is to try throwing a mock exception than the real one.

@Mock
Exception mockException;

observer.onError(mockException); 

Upvotes: 0

cdehning
cdehning

Reputation: 245

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!

Upvotes: 2

GVillani82
GVillani82

Reputation: 17439

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);
}

Upvotes: 9

Related Questions