使用Mockito进行JVM单元测试,以测试Retrofit2和RxJava的网络请求

ant*_*009 8 android mockito rx-java retrofit2

Android Studio 2.3 RC 1
Run Code Online (Sandbox Code Playgroud)

我正在使用MVP架构并希望运行JVM单元测试.

在我的模型中,我使用Retrofit2和RxJava从API获取电影.我想测试函数getPopularMovies(...)但是,这个函数会调用webserver.但是,在测试中我想以某种方式模拟这个并且只是测试onSuccess()onFailure()调用方法.

我的模型类看起来像这个片段只是为了保持简短:

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);
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

和界面:

public interface MovieListModelContract {
    interface PopularMovieResultsListener {
        void onFailure(String errorMessage);
        void onSuccess(Results popularMovies);
    }
    void getPopularMovies(PopularMovieResultsListener popularMovieResultsListener);
}
Run Code Online (Sandbox Code Playgroud)

我试图解决的问题是如何在getPopularMovies不实际调用网络服务的情况下使用Mockito进行测试?我只是想测试一下: popularMoviesResultsListener.onFailure(e.getMessage())将在收到电影失败popularMovieResultsListener.onSuccess(results);时被调用,并且在收到电影时 会被称为成功

我有这样的测试,但我不确定这是否正确:

@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);
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是如何模拟对网络请求的调用并测试预期的onSuccess()和onFailure()是否正常工作?

ant*_*009 3

我已经在这里完成了我的回答。我不确定这是否是最好的方法,希望其他人能够发表评论。

对于设置:

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(MovieListModelImpTest.this);

    movieListModelContract = new MovieListModelImp(mockMovieAPIService);

    RxJavaHooks.setOnIOScheduler(new Func1<Scheduler, Scheduler>() {
        @Override
        public Scheduler call(Scheduler scheduler) {
            return Schedulers.immediate();
        }
    });

    /* Override RxAndroid schedulers */
    final RxAndroidPlugins rxAndroidPlugins = RxAndroidPlugins.getInstance();
    rxAndroidPlugins.registerSchedulersHook(new RxAndroidSchedulersHook() {
        @Override
        public Scheduler getMainThreadScheduler() {
            return Schedulers.immediate();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

和撕下来

  @After
    public void tearDown() throws Exception {
        RxJavaHooks.reset();
        RxAndroidPlugins.getInstance().reset();
    }
Run Code Online (Sandbox Code Playgroud)

我的服务API

@GET("movie/popular")
Observable<Results> getPopular(@Query("api_key") String apikey);
Run Code Online (Sandbox Code Playgroud)

模拟

@Mock MovieAPIService mockMovieAPIService;
@Mock Observable<Results> mockCall;
@Mock ResponseBody responseBody;
@Mock MovieListModelContract.PopularMovieResultsListener mockPopularMoviesResultsListener;
private MovieListModelContract movieListModelContract;
@Captor ArgumentCaptor<Callback<List<Results>>> argumentCaptor;
Run Code Online (Sandbox Code Playgroud)

我的测试

 @Test
    public void shouldDisplaySuccessMessageOnSuccess() {
        final Results results = new Results();
        when(mockMovieAPIService.getPopular(anyString())).thenReturn(Observable.just(results));

        movieListModelContract.getPopularMovies(mockPopularMoviesResultsListener);

        verify(mockPopularMoviesResultsListener, never()).onFailure(anyString());
        verify(mockPopularMoviesResultsListener, times(1)).onSuccess(results);
    }
Run Code Online (Sandbox Code Playgroud)

我在这里给出了一个成功案例的例子,它可以作为一个例子。然而,一切似乎都正常。我只是想知道是否有更好的方法,或者我所做的有什么错误吗?

提前谢谢了