[英]JVM unit testing with Mockito for testing Retrofit2 and RxJava for network requests
Android Studio 2.3 RC 1
我正在使用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);
}
});
}
}
和界面:
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);
被調用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()是否正常工作?
想法是讓用戶TestSubscriber
在單元測試中斷言。
從Obtrofit返回Observable而不是void
(請注意,我已刪除的監聽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));
}
我已經設法在這里完成我的答案。 我不確定這是否是最好的方式,希望其他人可能會發表評論。
對於設置:
@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);
}
我舉了一個成功案例的例子,作為一個例子。 但是,因為一切似乎都可行。 我只是想知道是否有更好的方法,或者我做了什么錯誤?
提前謝謝了
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.