无法验证从RxJava用户模拟方法的调用 [英] Can't verify mock method call from RxJava Subscriber
问题描述
我试图单元测试presenter在我的Android应用程序。我试图测试方法如下:
@覆盖
公共布尔loadNextPage(){
如果(!误装入){
误装入= TRUE;
如果(mViewReference.get()!= NULL){
。mViewReference.get()showProgress();
}
mService.search(mSearchQuery,++ mCurrentPage)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(itemsPage - > {
误装入= FALSE;
mTotalPages = itemsPage.getPagination()getTotalPages()。
如果(mViewReference.get()!= NULL){
mViewReference.get()showMovies(itemsPage.getItems())。
}
},
错误 - > {
误装入= FALSE;
Log.d(LOG_TAG,error.toString());
});
}
返回mTotalPages == 0 || mCurrentPage< mTotalPages;
}
MSERVICE
是改造界面和 mService.search()
方法返回RxJava的观测< SearchResult所>
。我的单元测试code是这样的:
包mobi.zona presenters。进口org.junit.Test;
进口org.junit.runner.RunWith;
进口org.mockito.Mock;
进口org.mockito.runners.MockitoJUnitRunner;进口的java.util.ArrayList;
进口的java.util.List;进口com.example.api.Service;
进口com.example.model.Movie;
进口com.example.model.SearchResults;
进口com.example.views.MoviesListView;
进口rx.Observable;引入静态org.mockito.Mockito.times;
引入静态org.mockito.Mockito.verify;
进口静态org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class)
公共类搜索$ P $ {psenterTest @嘲笑
服务MSERVICE;
@嘲笑
MoviesListView mMoviesListView; @测试
公共无效testLoadNextPage()抛出异常{
字符串SEARCHQUERY =饥饿游戏;
SearchResult所的SearchResult =新的SearchResult();
清单<电影及GT;电影=新的ArrayList<>();
searchResults.setItems(电影); 当(mService.search(SEARCHQUERY,1))thenReturn(Observable.just(新的SearchResult()))。 MoviesList presenter presenter =新搜索presenter(mZonaService,mMoviesListView,SEARCHQUERY);
presenter.loadNextPage(); 验证(MSERVICE,时间(1)),搜索(SEARCHQUERY,1);
验证(mMoviesListView,时间(1))showProgress()。
验证(mMoviesListView,时间(1))showMovies(动画)。
}
}
问题是第三个验证(mMoviesListView,时间(1))showMovies(电影);
在线 - 它永诺失败。 Whem我试图调试这个测试我看到控制流从未进入 .subscribe(itemPage - {...
我觉得这件事情涉及到的事实,我订阅的 Schedulers.io()
话题,但对如何解决这一问题不知道。任何想法?
修改1:
改变了presenter采取计划
的作为构造函数的参数。更改测试是这样的:
@Test
公共无效testLoadNextPage()抛出异常{
字符串SEARCHQUERY =饥饿游戏;
SearchResult所的SearchResult =新的SearchResult();
清单<电影及GT;电影=新的ArrayList<>();
searchResults.setItems(电影); 当(mZonaService.search(SEARCHQUERY,1))thenReturn(Observable.just(新的SearchResult()))。 MoviesList presenter presenter =新搜索presenter(mZonaService,mMoviesListView,SEARCHQUERY,
Schedulers.test(),Schedulers.test());
presenter.loadNextPage(); 验证(mZonaService,时间(1)),搜索(SEARCHQUERY,1);
验证(mMoviesListView,时间(1))showProgress()。
验证(mMoviesListView,时间(1))showMovies(动画)。
}
不过获得这个测试失败消息:
通缉而不是调用:
mMoviesListView.showMovies([]);
- > 。在com。示例presenters.Search presenterTest.testLoadNextPage(搜索presenterTest.java:46)然而,有这个模拟的其他交互:
mMoviesListView.showProgress();
- > 。在com。示例presenters.Search presenter.loadNextPage(搜索presenter.java:41)
在我的应用程序交互器/用例/模型( MSERVICE
你的情况),负责指定计划
的操作(因为它知道更好它做什么样的操作)。
所以,请将您的 subscribeOn
到 MSERVICE
。之后,你的模拟将正常工作。
不断深入,如果现在你想测试 MSERVICE
我会建议你做的计划$ c将其养人 $ C>。换句话说 - 添加
Sheduler
作为构造函数的参数
公共类为MyService { 私人最终调度的TaskScheduler; 公共则将MyService(调度器的TaskScheduler){
this.taskScheduler =的TaskScheduler;
} // ... 公众可观察<&东西GT;查询(){
返回someObservable.subscribeOn(的TaskScheduler);
}
}
然后,在测试中可以使用 Schedulers.immediate()
和实际应用 Schedulers.io()
(或任何你喜欢,真的)。
I'm trying to unit test presenter in my Android app. Method I'm trying to test looks like this:
@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
is Retrofit interface and mService.search()
method returns RxJava's Observable<SearchResults>
. My unit test code looks like this:
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);
}
}
The problem is the third verify(mMoviesListView, times(1)).showMovies(movies);
line - it allways fails. Whem I'm trying to debug this test I see that control flow never goes into .subscribe(itemPage - {...
. I think that it's something related to the fact that I'm subscribing on Schedulers.io()
thread, but have no idea on how to fix this. Any ideas?
EDIT 1:
Changed the presenter to take Scheduler
's as constructor parameters. Changed test to look like this:
@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);
}
Still getting this test failure message:
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)
In my apps interactors/use-cases/model (mService
in your case) is responsible for specifying Scheduler
for the operation (since it knows better what kind of operation it does).
So, move your subscribeOn
to mService
. After that your mock will work fine.
Going deeper, if now you'll want to test mService
I would recommend you to make it "dependent" on Scheduler
. In other words - add Sheduler
as a constructor parameter.
public class MyService {
private final Scheduler taskScheduler;
public MyService(Scheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
// ...
public Observable<Something> query() {
return someObservable.subscribeOn(taskScheduler);
}
}
Then, in tests you can use Schedulers.immediate()
and for actual app Schedulers.io()
(or whatever you like, really).
这篇关于无法验证从RxJava用户模拟方法的调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!