Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test custom view with attribute

I'm having trouble to create a unit test for my custom view. I try to add an attribute and test it if my custom view class get it right.

Here's what my test looks like:

@RunWith(AndroidJUnit4.class)
@SmallTest
public class BaseRatingBarMinRatingTest {

    private Context mContext;

    @Before
    public void setUp(){
        mContext = InstrumentationRegistry.getTargetContext();
    }

    @Test
    public void constructor_should_setMinRating_when_attriSetHasOne() throws Exception{
        // 1. ARRANGE DATA
        float minRating = 2.5f;
        AttributeSet as = mock(AttributeSet.class);
        when(as.getAttributeFloatValue(eq(R.styleable.BaseRatingBar_srb_minRating), anyFloat())).thenReturn(minRating);


        // 2. ACT
        BaseRatingBar brb = new BaseRatingBar(mContext, as);


        // 3. ASSERT
        assertThat(brb.getMinRating(), is(minRating));
    }

  // ...

}

Which gets this Exception:

java.lang.ClassCastException: android.util.AttributeSet$MockitoMock$1142631110 cannot be cast to android.content.res.XmlBlock$Parser

I tried mocking TypeArray like this article did, but my view treats the mocked context as null.

Is there any good way to create a test case for custom view?

like image 516
Tomaz Wang Avatar asked Feb 24 '18 16:02

Tomaz Wang


People also ask

What is the attribute used for test method?

FindParamAttribute: You use this attribute to describe how an element can be found on the page. You set this attribute on test methods or share it across all test methods of a particular test class by setting it on the test class that contains the test methods that will use the FindParam definitions.


2 Answers

Consider using Robolectric, as it eliminates the need for mocks.

AttributeSet as =  Robolectric.buildAttributeSet().addAttribute(R.style.BaseRatingBar_srb_minRating, "2.5f").build()
BaseRatingBar brb = new BaseRatingBar(mContext, as);
like image 114
amram99 Avatar answered Oct 14 '22 11:10

amram99


I had a similar problem as you did. Like you, I wanted to test a custom View. This is how I solved it:

public class CustomViewTest {
    @Mock
    private Context context;
    @Mock
    private AttributeSet attributes;
    @Mock
    private TypedArray typedArray;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        when(context.obtainStyledAttributes(attributes, R.styleable.CustomView)).thenReturn(typedArray);
        when(typedArray.getInteger(eq(R.styleable.CustomView_customAttribute), anyInt())).thenReturn(23);
    }

    @Test
    public void constructor() {
        CustomView customView = new CustomView(context, attributes);
        assertEquals(23, customView.getCustomAttribute());
    }
}

And in my CustomView class:

public CustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    if (attrs != null) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
        customAttribute = a.getInteger(R.styleable.CustomView_customAttribute, 19);
        a.recycle();
    } else {
        customAttribute = 19;
    }
}

Try this approach, and post the exact error message if it doesn't work. Hope it helps.

like image 33
O.O.Balance Avatar answered Oct 14 '22 10:10

O.O.Balance