Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test this line of LayoutInflater.from() in android

Hi Am building a simple RecycleView Adapter and am trying to test all the methods of the adapter but the onCreateViewHolder is been dificult for me.

 @Override
public NewsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_news,parent,false);
return new NewsViewHolder(v);
}

I Try using mockito to build a mock of the viewGroup class and return a spy of the MockContext when getContext() is call but it seems to be that because am returning a MockContext LayoutInflater.from() return a null pointer exception.

This is my test

 @Test
public void testOnCreateViewHolder() throws Exception {
    ViewGroup vg = mock(ViewGroup.class);
    MockContext mockContext = new MockContext();
    MockContext spyContext = spy(mockContext);
    when(vg.getContext()).thenReturn(spyContext);


    NewsViewHolder vh = adapter.onCreateViewHolder(vg, 0);
    Assert.assertNotNull("Response cant be null",vh);
}

Thanks in advance.

like image 349
Alejandro Serret Avatar asked Nov 20 '15 18:11

Alejandro Serret


People also ask

How do I get LayoutInflater from context?

Use getLayoutInflater() to get the LayoutInflater instead of calling LayoutInflater. from(Context).

What is use of LayoutInflater in Android?

Stay organized with collections Save and categorize content based on your preferences. Instantiates a layout XML file into its corresponding View objects. It is never used directly.

Which file is inflated by LayoutInflater class?

The LayoutInflater class is used to instantiate the contents of layout XML files into their corresponding View objects. In other words, it takes an XML file as input and builds the View objects from it.


1 Answers

I came across this question when I was the same problem. I ended up solving it by myself.

Suppose that you have a simple onCreateViewHolder like this:

@Override
public TeamsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new NewsViewHolder(LayoutInflater
            .from(parent.getContext())
            .inflate(R.layout.fragment_news_view_holder, parent, false)
    );
}

Use PowerMock to mock the static instance of LayoutInflater. In the snippet below, I have annotated using numbered comments all the steps you need to take in order to make this work:

import android.test.mock.MockContext;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;

// 1. signal JUnit to run this test PowerMockRunner
@RunWith(PowerMockRunner.class)

// 2. signal PowerMock to prepare the static instance of LayoutInflater for testing
@PrepareForTest({LayoutInflater.class})
public class NewsRecyclerViewAdapterTest {

    // 3. LayoutInflater.from(context) returns an inflater, 
    // so we need to mock that one
    @Mock
    LayoutInflater mockInflater;

    @Mock
    View mockView;

    @Mock
    ViewGroup mockParent;

    private int dummyTestId;

    private MockContext mockContext;

    private NewsRecyclerViewAdapter adapter;

    @Before
    public void setUp() throws Exception {

        MockitoAnnotations.initMocks(this);

        dummyTestId = 0x10000;

        // 4. mock the static LayoutInflater in "LayoutInflater.from()" 
        // so that we can ask it to return a mockInflater that we moked above
        mockStatic(LayoutInflater.class);

        mockContext = new MockContext();

        adapter = new NewsRecyclerViewAdapter(Arrays.asList(new NewsItem(), new NewsItem(), new NewsItem()));
    }

    @Test
    public void onCreateViewHolderShouldReturnAValidViewHolder() throws Exception {

        // 5. mock the context that comes from parent ViewGroup
        when(mockParent.getContext()).thenReturn(mockContext);

        // 6. mock the inflater that is returned by LayoutInflater.from()
        when(LayoutInflater.from(mockContext)).thenReturn(mockInflater);

        // 7. pass anyInt() as a resource id to care of R.layout.fragment_news_view_holder in onCreateViewHolder()
        when(mockInflater.inflate(anyInt(), eq(mockParent), eq(false))).thenReturn(mockView);

        // call onCreateViewHolder() to act
        NewsViewHolder viewHolder = adapter.onCreateViewHolder(mockParent, dummyTestId);

        // OKAY straightfoward right?
        assertNotNull(viewHolder);

        // this is not very important but I recommend it,
        // it just returns the view sent to NewsViewHolder 
        // and verify it against the mockView that you inflated above
        assertEquals(viewHolder.getItemView(), mockView);
    }

}
like image 53
ceekays Avatar answered Oct 30 '22 09:10

ceekays