如何进行单元测试(使用JUnit或mockito)recyclelerview项目点击

14 android mocking android-testing android-recyclerview android-junit

我目前正在尝试单独测试recyclerview addonitemclick listner,使用junit或mockito.这是我的代码:

private void mypicadapter(TreeMap<Integer, List<Photos>> photosMap) {
    List<PhotoListItem> mItems = new ArrayList<>();

    for (Integer albumId : photosMap.keySet()) {
        ListHeader header = new ListHeader();
        header.setAlbumId(albumId);
        mItems.add(header);
        for (Photos photo : photosMap.get(albumId)) {
            mItems.add(photo);
        }


        pAdapter = new PhotoViewerListAdapter(MainActivity.this, mItems);
        mRecyclerView.setAdapter(pAdapter);
        //  set 5 photos per row if List item type --> header , else fill row with header.
        GridLayoutManager layoutManager = new GridLayoutManager(this, 5);
        layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if (mRecyclerView.getAdapter().getItemViewType(position) == PhotoListItem.HEADER_TYPE)
                    // return the number of columns so the group header takes a whole row
                    return 5;
                // normal child item takes up 1 cell
                return 1;
            }
        });
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.addOnItemTouchListener(new PhotoItemClickListener(MainActivity.this,
                new PhotoItemClickListener.OnItemClickListener() {
                    @Override
                    public void onItemClick(View view, int position) {
                        if (pAdapter.getItemViewType(position) == PhotoListItem.HEADER_TYPE) return;

                        Photos photo = pAdapter.getItem(position);
                        Intent intent = new Intent(MainActivity.this, DetailViewActivity.class);
                        intent.putExtra(PHOTO_DETAILS, photo);
                        ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                                MainActivity.this,

                                new Pair<>(view.findViewById(R.id.photoItem),
                                        getString(R.string.transition_name_photo))
                        );
                        ActivityCompat.startActivity(MainActivity.this, intent, options.toBundle());
                    }
                }));
    }
Run Code Online (Sandbox Code Playgroud)

有没有办法我可以进行单元测试:addOnItemTouchListener或OnItemClickListener/onitemclick,模拟功能等.我对单元测试很新,并且在网上查看了几个教程并且非常困惑.任何有关测试函数或任何建议的分步教程都会有所帮助.此外,此函数中任何其他可能的单元可测试方案都会有所帮助.谢谢!

Wik*_*ski 10

在单元测试中,拥有小的,可测试的代码块是很重要的,我宁愿使用单个可重用性的10个方法而不是所有操作的一个方法.

所有使用的输入都应作为参数传递给方法,而不是测试在给定输入时是否会收到预期的输出.

不要测试你不拥有的东西 - 测试View的onClick()是AOSP工作的一部分.您可以测试对onClickListener的反应.

你应该有一个处理逻辑的测试类.在您的测试中,您实例化此类以测试它并模拟其他所有内容(通常好的方法是通过构造函数传递依赖项)

例:

所以,如果你有像这样的方法

goToDetailActivity(Photo photo){...}
Run Code Online (Sandbox Code Playgroud)

我会把它包装在接口中,让我们调用它View.在View你提出你的逻辑必须调用的所有其他方法,并与视图相关,如与视图组件,导航等交互.你应该有你的逻辑类,让我们调用它Presenter:

public class Presenter {
Presenter(View:view) {
    this.view = view;
}

public void onPhotoClicked(Photo:photo) {
    if (shouldDetailScreenBeOpened())
        view.goToDetailActivity(Photo photo);
    else view.showError("error");
}

private boolean shouldDetailScreenBeOpened() {
    // do caclualtions here
    ...}
}
Run Code Online (Sandbox Code Playgroud)

我将我的适配器视为视图的一部分,因此它没有真正的逻辑.因此,将点击传递给Presenter你应该通过activity/fragment(View实现)传递给Presenter(如果有人对RxJava感兴趣,可以使用RxBinding库)并调用它的onPhotoClicked(photo)方法.

在测试中,你必须模拟你需要的东西(而不是测试的主题):

 View view= Mockito.mock(View.class);

 Presenter tested = Presenter(view); 

 Photo validPhoto = Mockitio.mock(Photo.class);
 Mockito.when(validPhoto.getUrl()).thanReturn("image.com")

 //call method which will be triggered on item click
 tested.onPhotoClicked(validPhoto)

 //Check if method was invoked with our object
 Mockito.verify(view).goToDetailActivity(validPhoto);

 //Check also not so happy path
 Photo invalidPhoto = Mockitio.mock(Photo.class);
 Mockito.when(invalidPhoto.getUrl()).thanReturn(null)

 //call method which will be triggered on item click
 tested.onPhotoClicked(invalidPhoto)
 Mockito.verify(view,never()).goToDetailActivity(invalidPhoto);
 Mockito.verify(view).showError("error")
Run Code Online (Sandbox Code Playgroud)

很好的盯着vogella mokcito教程.