我如何单元测试(使用JUnit或Mockito)recyclerview项目点击 [英] How do I unit test (with JUnit or mockito) recyclerview item clicks

查看:165
本文介绍了我如何单元测试(使用JUnit或Mockito)recyclerview项目点击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试使用junit或mockito对recyclerview addonitemclick列表器进行单元测试.这是我的代码:

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());
                    }
                }));
    }

有没有一种我可以进行单元测试的方法:addOnItemTouchListener或OnItemClickListener/onitemclick,模拟功能等.我对单元测试还很陌生,并且一直在网上查找一些教程,非常困惑.任何有关测试功能的分步教程或任何建议都将有所帮助.此外,此功能中任何其他可能的单元可测试场景也将有所帮助.谢谢!

解决方案

在单元测试中,拥有小的,可测试的小代码块是不切实际的,我宁愿有10种具有单一可重复性的方法,而不是针对所有操作的一种方法.

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

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

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

示例:

这样,如果您有类似

的方法

goToDetailActivity(Photo photo){...}

我将其包装在接口中,让其称为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
    ...}
}

我将适配器视为视图的一部分,因此没有真正的逻辑.因此,要将点击传递给Presenter,您应该将其通过活动/片段(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")

好的凝视点 vogella mokcito教程.

I am currently trying to unit test recyclerview addonitemclick listner, with either junit or mockito. here's my code:

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());
                    }
                }));
    }

Is there a way I can unit test : addOnItemTouchListener or OnItemClickListener/onitemclick ,mock the functionality etc. I am pretty new to unit testing and been looking up online at a couple of tutorials and pretty confused. Any step by step tutorial for testing functions or any suggestions would help.Also, any other possible unit testable scenarios in this function would be helpful. Thanks!

解决方案

In unit tests it's improtant to have small, testable chunks of code, I would rather have 10 methods with single resposinbility than one method for all actions.

All used inputs should be delivered as parameters to method, than you test if at given input you will receive expected output.

Don't test what you don't own - testing of View's onClick() is part of AOSP job. You can test how you react to onClickListener.

You should have class under test that handles the logic. Than in your test you instantiate this class to test it and mock everything else (usually good way to go is to pass dependencies through constructor)

Example:

So that way if you have method like

goToDetailActivity(Photo photo){...}

I would wrap it in interface, lets call it View. In View you put also all other methods that your logic must call and are view related like interacting with view components, navigation etc. Than you should have your logic class, lets call it 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
    ...}
}

I treat my adapters as part of view, so it has no real logic. So to pass clicks to Presenter you should pass it through activity/fragment (View implementation) to Presenter (if someone is fun of RxJava, RxBinding library can be used) and call it's onPhotoClicked(photo) method.

And in testing you have to mock things that you need (and are not subjects to test):

 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")

Good staring point vogella mokcito tutorial.

这篇关于我如何单元测试(使用JUnit或Mockito)recyclerview项目点击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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