Reputation: 977
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
Reputation: 2092
The easy way is to try throwing a mock exception than the real one.
@Mock
Exception mockException;
observer.onError(mockException);
Upvotes: 0
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
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