How do I unit test (with JUnit or mockito) recyclerview item clicks

冷暖自知 提交于 2019-12-20 18:10:13

问题


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!


回答1:


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.




回答2:


I would probably extract the anonymous inner class you're creating in addOnItemTouchListener into a separate class.

Then I would write the relevant (unit) tests for the onItemClick method.

This very much depends however on the overall context of your application and what exactly it is that you want to test.

The discussion about unit tests versus integration tests is pretty expensive and there is also some confusion and different opinions around what really is a unit test.

I would recommend starting to read more on the topic from Martin Fowler's excellent series of articles - e.g. https://martinfowler.com/bliki/UnitTest.html There's also another piece about test doubles in general, that should guide you with regards to whether you want to be using mocks or stubs: https://martinfowler.com/articles/mocksArentStubs.html



来源:https://stackoverflow.com/questions/42188261/how-do-i-unit-test-with-junit-or-mockito-recyclerview-item-clicks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!