我正在尝试在我的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;
}
mService
是Retrofit接口(interface),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);
}
}
问题是第三条
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);
}
仍然收到此测试失败消息:
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)
最佳答案
在我的应用程序中,交互器/用例/模型(在您的情况下为mService
)负责为操作指定Scheduler
(因为它更好地知道它执行哪种操作)。
因此,将subscribeOn
移到mService
。之后,您的模拟将正常工作。
更深入地讲,如果现在您要测试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);
}
}
然后,在测试中,您可以使用
Schedulers.immediate()
并将其用于实际的应用程序Schedulers.io()
(或任何您真正喜欢的东西)。