2017-02-24 96 views
7
Android Studio 2.3 RC 1 

我正在使用MVP体系结构并希望运行JVM单元测试。使用Mockito进行JVM单元测试以测试Retrofit2和RxJava的网络请求

在我的模型中,我使用Retrofit2和RxJava从API获取电影。我想测试这个函数getPopularMovies(...)但是,这个函数会调用web服务器。但是,在测试中,我想以某种方式模拟这种方式,只是测试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); 
      } 
     }); 
    } 
} 

和接口:

public interface MovieListModelContract { 
    interface PopularMovieResultsListener { 
     void onFailure(String errorMessage); 
     void onSuccess(Results popularMovies); 
    } 
    void getPopularMovies(PopularMovieResultsListener popularMovieResultsListener); 
} 

我的问题我试图解决的是怎么用的Mockito测试getPopularMovies没有实际调用网络服务?我只是想测试: 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); 
} 

所以我的问题是我怎么能嘲笑调用一个网络请求并测试了预期的onSuccess()和onFailure处()是否正常工作?

回答

1

我已成功地完成在这里我的答案。我不确定这是否是最好的方式,希望其他人能够发表评论。

对于设置:

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

而且推倒

@After 
    public void tearDown() throws Exception { 
     RxJavaHooks.reset(); 
     RxAndroidPlugins.getInstance().reset(); 
    } 

我的服务API

@GET("movie/popular") 
Observable<Results> getPopular(@Query("api_key") String apikey); 

嘲笑

@Mock MovieAPIService mockMovieAPIService; 
@Mock Observable<Results> mockCall; 
@Mock ResponseBody responseBody; 
@Mock MovieListModelContract.PopularMovieResultsListener mockPopularMoviesResultsListener; 
private MovieListModelContract movieListModelContract; 
@Captor ArgumentCaptor<Callback<List<Results>>> argumentCaptor; 

我的测试

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

我给出了一个成功案例的例子,它可以作为例子工作。但是,因为一切似乎都很好。我只是想知道有没有更好的方法去做,或者我做了什么错误?

非常感谢提前

+0

我不认为你已经按照单元测试你的课程所需要的那样嘲笑了真实的网络请求。我试图在我的回答中解决这个问题:) –

+0

@PravinSonawane这是我的错误。我粘贴了错误的测试代码片段。我现在已经更新了我的答案。这里我使用when(...),thenReturn。模拟MovieAPIService.getPopular(..)以返回正确的结果。然后我验证正确的onFailure()和onSuccess()被称为正确的次数。这只是测试业务逻辑,而不是对网络进行真正的呼叫。测试独立于任何外部依赖。 – ant2009

2

这个想法是用户TestSubscriber在单元测试中断言。

返回从改造,而不是可观测空白

(请注意,我已删除的监听PopularMovieResultsListener与您使用RxJava随着RxJava您可以订阅返回的观察到的,使用onNext()onComplete()onError()代替。)

public class MovieListModelImp implements MovieListModelContract { 

    @Override 
    public Observable<Results> getPopularMovies() { 
     /** Return the Observable from Retrofit. */ 
     return mMovieAPIService.getPopular(Constants.MOVIES_API_KEY); 
} 

使用在单元测试中TestSubscriber断言

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

} 
+0

谢谢我会试一试。但是,我想让我的听众成为我设计的一部分。 – ant2009

+0

我已经设法回答我自己的问题,并张贴在这里。它适用于成功和失败的情况。我嘲笑了我的听众。如果你认为我能做的更好,也许你可以发表评论。 – ant2009

相关问题