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

私はMVPアーキテクチャを使用しており、JVMユニットテストを実行します。ネットワークリクエスト用のRetrofit2とRxJavaをテストするためのMockitoによるJVMユニットテスト

私のモデルでは、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); 
    } 

私は例として、[OK]を動作しますここでは成功例一例を与えています。しかし、すべてがうまくいくように見えます。私はそれを行うより良い方法があるのだろうか、あるいは私がやったことに間違いがあるのだろうかと疑問に思っています。

ありがとうございます。

+0

あなたのクラスを単体テストするのに必要な実際のネットワークリクエストを嘲笑していないと思います。私は私の答えでこれを解決しようとしました:) –

+0

@PravinSonawaneそれは私の間違いでした。テスト用に間違ったコードスニペットを貼り付けました。私は今私の答えを更新しました。ここで私はwhen(...)。then returnを使用しています。 MovieAPIService.getPopular(..)をモックして正しい結果を返すには次に、正しいonFailure()とonSuccess()が正しい回数呼び出されたことを確認します。これはビジネスロジックをテストするだけで、ネットワークへの実際の呼び出しを行わないことです。このテストは、外部依存関係から独立しています。 – ant2009

2

ユーザーはTestSubscriberにユニットテストでアサートすることを考えています。

戻る代わりに、ボイド

のレトロフィットから観察可能(あなたがRxJavaを使用していると私はリスナーPopularMovieResultsListenerを削除したことに注意してください。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

関連する問題