Android自動化測試|Espresso-list

簡介

當處理列表時(如RecyclerView or AdapterView)時,你想要的元素並不在屏幕上,因爲列表的特性。

Espresso提供了特殊的方法來處理兩類列表:

  • RecyclerView
  • AdapterView

AdapterView

繼承AdapterView的類有很多,如ListView,GridView,Spinner,等。
而尋找元素使用onData().

例子

例子使用ListView。採用兩個Adapter:SimpleAdapter和自定義Adapter。

SimpleAdapter

代碼

public class ListViewActivity extends AppCompatActivity{

    private ListView lt1;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listview);

        List<Map<String, String>> listems = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Map<String, String> listem = new HashMap<>();
            listem.put("STR", String.format(Locale.getDefault(), "item %d", i));
            listem.put("LEN", String.valueOf(i));
            listems.add(listem);
        }

        SimpleAdapter adapter = new SimpleAdapter(this, listems,
                R.layout.adapter_simple, new String[] { "STR", "LEN"},
                new int[] {R.id.simple_item,R.id.simple_len});

        lt1=(ListView)findViewById(R.id.list);
        lt1.setAdapter(adapter);

    }
}

測試代碼

@RunWith(AndroidJUnit4.class)
public class ListViewActivityTest {

    @Rule
    public ActivityTestRule<ListViewActivity> mActivityRule = new ActivityTestRule<>(
            ListViewActivity.class);

    @Test
    public void findItemAndClick(){

        onData(allOf(is(Matchers.instanceOf(Map.class)),
                hasEntry(equalTo("STR"), is("item 40")))).perform(click());

    }

    @Test
    public void findItemAndClickCustom() {
        onData(withItemContent("item 40")).perform(click());
    }


    @Test
    public void findItemAndClickChild() {
        onData(withItemContent("item 40")).onChildView(withId(R.id.simple_len)).perform(click());
    }

    public static Matcher<Object> withItemContent(final Matcher<String> itemTextMatcher) {
        return new BoundedMatcher<Object, Map>(Map.class) {
            @Override
            public boolean matchesSafely(Map map) {
                return hasEntry(equalTo("STR"), itemTextMatcher).matches(map);
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("with item content: ");
                itemTextMatcher.describeTo(description);
            }
        };
    }

    public static Matcher<Object> withItemContent(String expectedText) {
        return withItemContent(equalTo(expectedText));
    }
}

自定義Adapter

public class ListViewActivity2 extends AppCompatActivity {

    private ListView lt1;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listview);

        List<SearchItem> listems = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            SearchItem item = new SearchItem();
            item.setKeyword(String.format(Locale.getDefault(), "item %d", i));
            listems.add(item);
        }

        MyAdapter adapter = new MyAdapter(this, listems);

        lt1=(ListView)findViewById(R.id.list);
        lt1.setAdapter(adapter);

    }

    public class ViewHolder {
        TextView mText;
    }

    public class MyAdapter extends BaseAdapter {

        private LayoutInflater mInflater;
        private List<SearchItem> mItems;
        public MyAdapter(Context context, List<SearchItem> items) {
            this.mInflater = LayoutInflater.from(context);
            mItems = items;
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mItems.size();
        }

        @Override
        public SearchItem getItem(int arg0) {
            // TODO Auto-generated method stub
            return mItems.get(arg0);
        }

        @Override
        public long getItemId(int arg0) {
            // TODO Auto-generated method stub
            return arg0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 顯示優化(只要之前顯示過的就可以不再再次從佈局文件讀取,直接從緩存中讀取——ViewHolder的作用)
            // 其實是setTag和getTag中Tag的作用
            ViewHolder holder = null;
            if (convertView == null) {// 如果是第一次顯示該頁面(要記得保存到viewholder中供下次直接從緩存中調用)

                holder = new ViewHolder();

                convertView = mInflater.inflate(R.layout.adapter_simple2, null);
                // 以下爲保存這一屏的內容,供下次回到這一屏的時候直接refresh,而不用重讀佈局文件
                holder.mText = (TextView) convertView.findViewById(R.id.simple2_text);
                convertView.setTag(holder);

            } else {// 如果之前已經顯示過該頁面,則用viewholder中的緩存直接刷屏

                holder = (ViewHolder) convertView.getTag();
            }

            SearchItem item = mItems.get(position);
            holder.mText.setText(item.getKeyword());

            return convertView;
        }
    }
}
public class SearchItem {
    private String keyword;

    public SearchItem() {}

    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }

    public String getKeyword() {
        return keyword;
    }
}

測試代碼

@RunWith(AndroidJUnit4.class)
public class ListViewActivity2Test {

    @Rule
    public ActivityTestRule<ListViewActivity2> mActivityRule = new ActivityTestRule<>(
            ListViewActivity2.class);

    @Test
    public void findItemAndClick(){

        onData(allOf(is(instanceOf(SearchItem.class)),
                teacherSearchItemWithName("item 40"))).perform(click());

        onData(allOf(is(instanceOf(SearchItem.class)), teacherSearchItemWithName("item 40")))
                .inAdapterView(withId(R.id.list)).perform(click());
    }


    public static Matcher<Object> teacherSearchItemWithName(final String name) {
        return new BoundedMatcher<Object, SearchItem>(SearchItem.class) {
            @Override
            protected boolean matchesSafely(SearchItem item) {
                return item != null
                        && !TextUtils.isEmpty(item.getKeyword())
                        && item.getKeyword().equals(name);
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("SearchItem has Name: " + name);
            }
        };
    }
}

區別

兩個adapter一個採用map,一個採用SearchItem,在測試代碼中都是用 instance(map.class)和instance(SearchItem)來尋找需要的對應的adapter,進而找到元素。即時通過數據匹配找元素。

onData尋找元素時會自動滾動去顯示匹配元素。

RecyclerView

對RecycleView採用onView先得到RecycleView這個元素,然後通過perform執行動作更新子元素。

官網地址
官方源碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章