无法验证来自RxJava订阅服务器的模拟方法调用

Fyo*_*tov 6 java android unit-testing rx-java retrofit

我正在尝试在我的Android应用中单独测试演示者.方法我试图测试看起来像这样:

@Override
public boolean loadNextPage() {
    if (!mIsLoading) {
        mIsLoading = true;
        if (mViewReference.get() != null) {
            mViewReference.get().showProgress();
        }
        mService.search(mSearchQuery, ++mCurrentPage)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(itemsPage -> {
                            mIsLoading = false;
                            mTotalPages = itemsPage.getPagination().getTotalPages();
                            if (mViewReference.get() != null) {
                                mViewReference.get().showMovies(itemsPage.getItems());
                            }
                        },
                        error -> {
                            mIsLoading = false;
                            Log.d(LOG_TAG, error.toString());
                        });
    }
    return mTotalPages == 0 || mCurrentPage < mTotalPages;
}
Run Code Online (Sandbox Code Playgroud)

mService是Retrofit接口和mService.search()方法返回RxJava的Observable<SearchResults>.我的单元测试代码如下所示:

package mobi.zona.presenters;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.ArrayList;
import java.util.List;

import com.example.api.Service;
import com.example.model.Movie;
import com.example.model.SearchResults;
import com.example.views.MoviesListView;
import rx.Observable;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class SearchPresenterTest {

    @Mock
    Service mService;
    @Mock
    MoviesListView mMoviesListView;

    @Test
    public void testLoadNextPage() throws Exception {
        String searchQuery = "the hunger games";
        SearchResults searchResults = new SearchResults();
        List<Movie> movies = new ArrayList<>();
        searchResults.setItems(movies);

        when(mService.search(searchQuery, 1)).thenReturn(Observable.just(new SearchResults()));

        MoviesListPresenter presenter = new SearchPresenter(mZonaService, mMoviesListView, searchQuery);
        presenter.loadNextPage();

        verify(mService, times(1)).search(searchQuery, 1);
        verify(mMoviesListView, times(1)).showProgress();
        verify(mMoviesListView, times(1)).showMovies(movies);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是第三verify(mMoviesListView, times(1)).showMovies(movies);行 - 它总是失败.我正在尝试调试此测试,我发现控制流程从未进入过.subscribe(itemPage - {....我认为这与我订阅Schedulers.io()线程这一事实有关,但不知道如何解决这个问题.有任何想法吗? 编辑1: 更改了演示者以将其Scheduler作为构造函数参数.将测试更改为如下所示:

@Test
public void testLoadNextPage() throws Exception {
    String searchQuery = "the hunger games";
    SearchResults searchResults = new SearchResults();
    List<Movie> movies = new ArrayList<>();
    searchResults.setItems(movies);

    when(mZonaService.search(searchQuery, 1)).thenReturn(Observable.just(new SearchResults()));

    MoviesListPresenter presenter = new SearchPresenter(mZonaService, mMoviesListView, searchQuery,
            Schedulers.test(), Schedulers.test());
    presenter.loadNextPage();

    verify(mZonaService, times(1)).search(searchQuery, 1);
    verify(mMoviesListView, times(1)).showProgress();
    verify(mMoviesListView, times(1)).showMovies(movies);
}
Run Code Online (Sandbox Code Playgroud)

仍然收到此测试失败消息:

Wanted but not invoked:
mMoviesListView.showMovies([]);
-> at com.example.presenters.SearchPresenterTest.testLoadNextPage(SearchPresenterTest.java:46)

However, there were other interactions with this mock:
mMoviesListView.showProgress();
-> at com.example.presenters.SearchPresenter.loadNextPage(SearchPresenter.java:41)
Run Code Online (Sandbox Code Playgroud)

Dmi*_*sev 2

在我的应用程序中,交互者/用例/模型(mService在您的情况下)负责指定Scheduler操作(因为它更好地知道它执行哪种操作)。

因此,将您的移动subscribeOnmService. 之后你的模拟就会正常工作。

更深入地说,如果现在您想测试,mService我建议您使其“依赖于” Scheduler. 换句话说 - 添加Sheduler为构造函数参数。

public class MyService {

    private final Scheduler taskScheduler;

    public MyService(Scheduler taskScheduler) {
        this.taskScheduler = taskScheduler;
    }

    // ...

    public Observable<Something> query() {
        return someObservable.subscribeOn(taskScheduler);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在测试中您可以将Schedulers.immediate()和 用于实际应用程序Schedulers.io()(或者您真正喜欢的任何内容)。