私はMVPパターンを使用してAndroidアプリケーションを作成しています。 私はRetrofit 2とRxJavaを使用しています。アプリケーションは正常に動作しますRxJava + Retrofit 2ユニットテスト奇妙なエラー
しかし、ユニットテストで私は奇妙なエラーが発生しています。同じテストコードが時々通過し、時には失敗します。
public class AlbumPresenterImpl implements AlbumPresenter {
private AlbumView view;
private MediaType type;
private List<Album> albums;
private MediaService mediaService;
public AlbumPresenterImpl(AlbumView view, MediaService mediaService, MediaType type) {
this.view = view;
this.mediaService = mediaService;
this.type = type;
}
@Override
public void getAlbums() {
Observable<List<Album>> observable;
if (type.equals(MediaType.VIDEO)) {
observable = mediaService.getVideoAlbums();
} else {
observable = mediaService.getPhotoAlbums();
}
observable.doOnSubscribe(view::showProgress)
.doAfterTerminate(view::hideProgress)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
albums = items;
view.showAlbums(albums);
}, throwable -> {
view.showError(throwable.getLocalizedMessage());
});
}
@Override
public void onResume() {
if (albums == null) {
getAlbums();
}
}
@Override
public void onDestroy() {
}
}
をテストしている
エラーこのメッセージを表示して
Wanted but not invoked:
albumView.showProgress();
-> at kz.afckairat.kairat.media.AlbumPresenterTest.checkGetPhotoAlbums(AlbumPresenterTest.java:66)
Actually, there were zero interactions with this mock.
Testクラス
public class AlbumPresenterTest {
enter code here
private MediaService mediaService;
private AlbumView albumView;
private AlbumPresenterImpl photoAlbumPresenter;
@Before
public void setUp() throws Exception {
albumView = mock(AlbumView.class);
mediaService = mock(MediaService.class);
photoAlbumPresenter = new AlbumPresenterImpl(albumView, mediaService, MediaType.PHOTO);
RxAndroidPlugins.getInstance().registerSchedulersHook(new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
});
}
@After
public void tearDown() {
RxAndroidPlugins.getInstance().reset();
}
@Test
public void checkGetPhotoAlbums() {
List<Album> albums = getAlbumList();
when(mediaService.getPhotoAlbums()).thenReturn(Observable.just(albums));
photoAlbumPresenter.getAlbums();
verify(albumView).showProgress();
verify(albumView).showAlbums(albums);
verify(albumView).hideProgress();
}
@Test
public void checkGetPhotoAlbumError() {
String msg = "Error";
when(mediaService.getPhotoAlbums()).thenReturn(Observable.error(new IOException(msg)));
photoAlbumPresenter.getAlbums();
verify(albumView).showProgress();
verify(albumView).showError(msg);
verify(albumView).hideProgress();
}
private List<Album> getAlbumList() {
List<Album> albums = new ArrayList<>();
Album album = new Album(1, "Test1", "test1.jpg", "01.01.2016", 2);
albums.add(album);
album = new Album(2, "Test2", "test2.jpg", "01.01.2016", 2);
albums.add(album);
return albums;
}
}
プレゼンタークラスがなぜ時々テストは合格しませんか?
ありがとうございます!
=================================
更新
@Fredが書いたように問題はGithubのa linkから
コードを撮影したスケジューラ
public class RxSchedulersOverrideRule implements TestRule {
private final RxJavaSchedulersHook mRxJavaSchedulersHook = new RxJavaSchedulersHook() {
@Override
public Scheduler getIOScheduler() {
return Schedulers.immediate();
}
@Override
public Scheduler getNewThreadScheduler() {
return Schedulers.immediate();
}
};
private final RxAndroidSchedulersHook mRxAndroidSchedulersHook = new RxAndroidSchedulersHook() {
@Override
public Scheduler getMainThreadScheduler() {
return Schedulers.immediate();
}
};
// Hack to get around RxJavaPlugins.reset() not being public
// See https://github.com/ReactiveX/RxJava/issues/2297
// Hopefully the method will be public in new releases of RxAndroid and we can remove the hack.
private void callResetViaReflectionIn(RxJavaPlugins rxJavaPlugins)
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Method method = rxJavaPlugins.getClass().getDeclaredMethod("reset");
method.setAccessible(true);
method.invoke(rxJavaPlugins);
}
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
RxAndroidPlugins.getInstance().reset();
RxAndroidPlugins.getInstance().registerSchedulersHook(mRxAndroidSchedulersHook);
callResetViaReflectionIn(RxJavaPlugins.getInstance());
RxJavaPlugins.getInstance().registerSchedulersHook(mRxJavaSchedulersHook);
base.evaluate();
RxAndroidPlugins.getInstance().reset();
callResetViaReflectionIn(RxJavaPlugins.getInstance());
}
};
}
}にありました!
とテストクラスの
@Rule
public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule();
メインスレッドのスケジュールをオーバーライドして即座に返すようなサウンドはありますが、あなたは '' Schedulers.io() ''をオーバーライドしませんでした。だから、もし私がこの権利を考えているならば、テストは1つのスレッドで実行され、プレゼンターのメンバーは両方とも別のメンバーになり、結果としてあなたは予想どおりの競争条件を生み出します。あなたはテストのために試してみることができます。ちょうど "即時"のスケジューラをどこでも使うことができます。 – Fred
ありがとう!あなたは正しかった。スケジューラに問題がありました – kamadi
他の人も同様に恩恵を受けることができるように、より完全な回答を書いていきます。 – Fred