如何在单元测试中正确地模拟Picasso?

3

我正在尝试进行以下简单的Presenter测试:

public class NewsPresenterTest {
private static List<News> NEWS_HEADLINES;

@Mock
private NewsRepository mNewsRepository;

@Mock
private Picasso mPicassoClient;

@Mock
private ChromeTabsWrapper mChromeTabsWrapper;

@Mock
private NewsContract.View mNewsView;

@Captor
private ArgumentCaptor<NewsDataSource.LoadNewsCallback> mLoadNewsCallbackCaptor;

private NewsPresenter mNewsPresenter;

@Before
public void setupNewsPresenter() {
    // inject the mocks
    MockitoAnnotations.initMocks(this);

    mNewsPresenter = new NewsPresenter(mNewsRepository, new CompositeDisposable(), mPicassoClient, mChromeTabsWrapper);
    mNewsPresenter.subscribe(mNewsView);

    NEWS_HEADLINES = Lists.newArrayList(...);
}

@Test
public void loadHeadlinesNewsFromRepositoryAndLoadIntoView(){
          // verify certain behavior 
    }
}

我似乎无法嘲笑mPicassoClient,结果得到以下异常:

java.lang.ExceptionInInitializerError
at sun.reflect.GeneratedSerializationConstructorAccessor3.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
...more 
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
at android.os.Looper.getMainLooper(Looper.java)
at com.squareup.picasso.Picasso.<clinit>(Picasso.java:109)
... and more

根据堆栈信息,异常发生在mocks被初始化时,更准确地说是在这一行代码:MockitoAnnotations.initMocks(this); 因此,模拟Picasso.class失败了。我做错了什么?
1个回答

2

Picasso类不应该出现在你的Presenter中。将Picasso的调用移动到Fragment中。请注意,这并不能防止它被测试覆盖(以一种不太明确的方式):

之前的代码:

newsRepository.getNews(date) 
   .subscribe(news ->
      Picasso.loadImage(news.getImageUrl()))

重构:

newsRepository.getNews(date)
    .subscribe(news ->
        view.loadImage(news.getImageUrl()))

这里的 view 指的是 Model/View/Presenter 中的 View,由你的 Activity 或 Fragment 实现。在你的 Fragment 或 Activity 中:

@Override
public void loadImage(String url) {
    Picasso.loadImage(url);
}

1
如果我可以提出两个澄清问题。1.因此,图像加载客户端应直接注入到“View”中?这被认为是一种好的做法吗?2.我考虑将客户端注入到Presenter中,以便它负责将其进一步传递给View,这样View将独立于从Presenter接收的图像加载客户端,这种推理是否不正确? - Catalin Ghita
1
@CatalinGhita 这些是非常好的问题,表明你已经仔细思考过了。问题的一部分可能是将Picasso视为客户端而不是仅仅是一个视图层帮助程序。在我看到的大多数使用GlidePicasso的示例中,只是在ViewHolder、Activity或Fragment中直接静态引用Glide或Picasso。 - David Rawson
1
感谢您的澄清 - 把Picasso视为视图层帮助程序确实简化了我的思考问题。因此,在测试视图时,我可能需要提供一个简单的Picasso模拟实现,但这排除了直接模拟它作为问题所问的解决方法,从而解决了这个问题。尽管这不是我最初想要的,但您的回答提供了一些有用的见解,因此我会接受它。再次感谢! - Catalin Ghita

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接