我有以下方法使用Retrofit服务接口从API获取一些数据,然后与view
接口进行交互。
@Override
@VisibleForTesting
public void fetchPhotos(@Nullable PhotosService service, @Nullable Scheduler subscribeOn) {
view.showLoading();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.PLACEHOLDER_API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
if (service == null) service = retrofit.create(PhotosService.class);
if (subscribeOn == null) subscribeOn = Schedulers.newThread();
service.listPhotos()
.subscribeOn(subscribeOn)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(photoList -> {
Log.d(TAG, "got photos " + photoList.toString());
view.unshowLoading();
}, throwable -> {
Log.d(TAG, "error " + throwable.toString());
view.unshowLoading();
view.displayError(throwable.toString(), v -> fetchPhotos());
});
}
我想测试在onNext中调用view.unshowLoading()
。
这是我的测试:
@Test
public void viewUnshowsLoadingAfterFetchingPhotos() {
PhotosListView view = Mockito.mock(PhotosListView.class);
PhotosListPresenter presenter = new PhotosListPresenterImpl(view);
presenter.fetchPhotos(() -> Observable.create(new Observable.OnSubscribe<List<Photo>>() {
@Override
public void call(Subscriber<? super List<Photo>> subscriber) {
subscriber.onNext(new ArrayList<Photo>());
}
}), Schedulers.immediate());
Mockito.verify(view).unshowLoading();
}
我明确传入Scheduler
Schedulers.immediate()
以确保在订阅主题上立即调用onNext()
。
当我通过我的方法调试时,onNext()
未被调用。
我做错了什么或者我怎么能最好地测试这个?
编辑: This article让我了解了一些事情:
如果要更改执行操作的线程 你可以调用subscribeOn()。要回到主线程使用 observeOn(AndroidSchedulers.mainThread())。但请注意 每当您强制操作到特定线程时,它都会 总是订阅asynchronou s。
当我省略
时 .subscribeOn(subscribeOn)
.observeOn(AndroidSchedulers.mainThread())
部分,测试按预期工作。当没有传入调度程序时,我已将我的方法重新排列为observeOn()
或subscribeOn()
中没有调用:
public void fetchPhotos(@Nullable PhotosService service, @Nullable Scheduler subscribeOn, @Nullable Scheduler observeOn) {
view.showLoading();
if (service == null) service = createService();
Observable<List<Photo>> observable = service.listPhotos();
if (subscribeOn != null) observable = observable.subscribeOn(subscribeOn);
if (observeOn != null) observable = observable.observeOn(observeOn);
observable.subscribe(photoList -> {
Log.d(TAG, "got photos " + photoList.toString());
view.unshowLoading();
}, throwable -> {
Log.d(TAG, "error " + throwable.toString());
view.unshowLoading();
view.displayError(throwable.toString(), v -> fetchPhotos());
});
}
看起来有点笨拙,但有效。
任何想法仍然欢迎:)
答案 0 :(得分:1)
第一个样本很好,只需注入ui调度程序并使用它。在您的测试中注入类似立即调度程序的东西,并在生产中注入Android ui调度程序。一般来说,最好不要在类中硬编码依赖项,而是注入它们。这是依赖注入可能有所帮助的案例之一。
关于subscribeOn
的说明:您不需要在改装时使用它,因为改装将无论如何都会在默认线程上执行操作。还命名调度程序&#34; subscribeOn&#34;并且&#34;观察&#34;没有多大意义,因为您可能希望使用相同的调度程序传递给subscribeOn()
和observeOn()
。给出更有意义的名字会更好,因为它们代表了什么,例如&#34; backgroundScheduler&#34;和&#34; uiScheduler&#34;