Android Studio 2.3 RC 1
I am using the MVP architecture and want to run JVM unit tests.
In my Model I am using Retrofit2 and RxJava to fetch movies from a API. I want to test the function getPopularMovies(...)
However, this function will make a call to the webserver. However, in the test I want to mock this somehow and just test the onSuccess()
and onFailure()
methods are called.
My model class looks like this snippet only to keep it short:
public class MovieListModelImp implements MovieListModelContract {
@Override
public void getPopularMovies(PopularMovieResultsListener popularMovieResultsListener) {
mSubscription = mMovieAPIService.getPopular(Constants.MOVIES_API_KEY)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Results>() {
@Override
public void onCompleted() {
Timber.d("onCompleted");
}
@Override
public void onError(Throwable e) {
Timber.e(e, "onError");
popularMovieResultsListener.onFailure(e.getMessage());
}
@Override
public void onNext(Results results) {
Timber.d("onNext %d", results.getResults().size());
popularMovieResultsListener.onSuccess(results);
}
});
}
}
And the interface:
public interface MovieListModelContract {
interface PopularMovieResultsListener {
void onFailure(String errorMessage);
void onSuccess(Results popularMovies);
}
void getPopularMovies(PopularMovieResultsListener popularMovieResultsListener);
}
My problem I am trying to solve is how can I use Mockito to test the getPopularMovies
without actually calling the network service? I just want to test that:
popularMoviesResultsListener.onFailure(e.getMessage())
will be called on failure to get movies
and
popularMovieResultsListener.onSuccess(results);
will be called on success when movies are recieved
I have a test like this but I am not sure if this is correct:
@Test
public void shouldDisplaySuccessWhenNetworkSucceeds() {
/* Results is the movie results class that is returned */
Results results = new Results();
/* Mock the listener */
MovieListModelContract.PopularMovieResultsListener mockPopularMoviesResultsListener =
Mockito.mock(MovieListModelContract.PopularMovieResultsListener.class);
/* Real instance of the model */
MovieListModelImp movieListModelImp = new MovieListModelImp();
/* Call getPopularMovies with mock listener - However, this will still make a real network request */
movieListModelImp.getPopularMovies(mockPopularMoviesResultsListener);
/* Verify - but I think I have got this all wrong */
verify(mockPopularMoviesResultsListener, times(1)).onSuccess(results);
}
So my problem is how can I mock a call to a network request and test the expected onSuccess() and onFailure() is working correctly?
How to test RxJava and Retrofit 1 Get rid of the static call - use dependency injection 2 Create the test class 3 Mock and test More ...
Unit Tests are test cases which runs on JVM, used to find bugs in code at the early stages, it is not for the product, but for the developer to write good bug-free code in his lifetime. It is base for TDD, and easy to write, maintain and understand.
In contrast, a Mock object will by default just return null for any method that is called. At the beginning of the post we had two main concerns with testing complex objects: failures in the test can be caused by poor implementation from an object we inject. With Mockito we were able to overcome both of these issues.
@IgorGanapolsky You can't directly test REST APIs in an Android app in JUnit if you use any class that references the Android SDK, as JUnit doesn't load the Android classes.
The idea is to user TestSubscriber
to assert in unit tests.
Return the Observable from Retrofit instead of void
(Note that I have removed the listener PopularMovieResultsListener
as you are using RxJava. With RxJava you can subscribe to the returned Observable and use onNext()
, onComplete()
, onError()
instead.)
public class MovieListModelImp implements MovieListModelContract {
@Override
public Observable<Results> getPopularMovies() {
/** Return the Observable from Retrofit. */
return mMovieAPIService.getPopular(Constants.MOVIES_API_KEY);
}
Use
TestSubscriber
in your unit tests to assert
@Mock
MovieAPIService mMovieAPIService
@Test
public void shouldDisplaySuccessWhenNetworkSucceeds() {
/* Results is the movie results class that is returned */
Results expectedResults = new Results();
MovieListModelImp movieListModelImp = new MovieListModelImp();
//Mock mMovieAPIService which is the actual network call
when(mMovieAPIService.getPopular(any(String.class)).thenReturn(Observable.just(results));
Observable<Results> actualResultsObservable = movieListModelImp.getPopularMovies();
TestObserver<Results> testObserver = actualResultsObservable.test();
testObserver.assertSubscribed();
testObserver.assertResult(expectedResults);
//verify
verify(mMovieAPIService, times(1)).getPopular(any(String.class));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With