无法验证从RxJava用户模拟方法的调用 [英] Can't verify mock method call from RxJava Subscriber

查看:233
本文介绍了无法验证从RxJava用户模拟方法的调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图单元测试presenter在我的Andr​​oid应用程序。我试图测试方法如下:

  @覆盖
公共布尔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<>();
        sea​​rchResults.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<>();
    sea​​rchResults.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 我会建议你做的计划。换句话说 - 添加 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆