验证在RxJava订阅服务器的onNext中调用该方法

asc*_*sco 5 android mockito rx-java

我有以下方法使用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());
            });
}
Run Code Online (Sandbox Code Playgroud)

我想测试view.unshowLoading()onNext中调用的那个.

这是我的测试:

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


}
Run Code Online (Sandbox Code Playgroud)

我明确传入Scheduler Schedulers.immediate()以确保onNext()在订阅线程上立即调用.

当我通过我的方法调试时,onNext()没有被调用.我做错了什么或者我怎么能最好地测试这个?

编辑: 这篇文章带给我的东西:

如果要更改执行操作的线程,可以调用subscribeOn().要返回主线程,请使用observeOn(AndroidSchedulers.mainThread()).但是,请注意, 每当您将操作强制到特定线程时,它总是会使订阅异步.

当我省略了

        .subscribeOn(subscribeOn)
        .observeOn(AndroidSchedulers.mainThread())
Run Code Online (Sandbox Code Playgroud)

部分,测试按预期工作.我已经重新安排我的方法没有调用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());
    });
}
Run Code Online (Sandbox Code Playgroud)

看起来有点笨拙,但有效.

任何想法仍然欢迎:)

mem*_*izr 1

第一个示例很好,只需注入 ui 调度程序并使用它即可。在测试中注入类似即时调度程序的东西,并在生产中注入 Android ui 调度程序。一般来说,最好不要在类中硬编码依赖项,而是注入它们。这是依赖注入可以提供帮助的情况之一。

注意subscribeOn:您不需要将其与改造一起使用,因为改造无论如何都会在默认线程上执行操作。此外,将调度程序命名为“subscribeOn”和“observeOn”没有多大意义,因为您可能希望使用相同的调度程序来传递到subscribeOn()observeOn()。考虑到它们所代表的含义,最好给它们更有意义的名称,例如“backgroundScheduler”和“uiScheduler”