Espresso 自动化测试(七)- Viewpager与Listview的使用
前面谈到的Listview的测试都是单独的一个。但是往往现在的App的设计基本是ViewPager+Listview/RecyclerView 这里的RecyclerView的处理与ListView不一致,我们会放到后续进行讲解。
在前面我们有提及过,我们查找控件都是需要有个唯一的区别该控件的条件。如何该条件同时满足其他控件的话,程序就会报 AmbiguousViewMatcherException 的异常。那么我们要怎么处理这种情况呢。
ViewPager+ListView的实现
首先讲解决方法前我们先说下这个的实现的。因为这个不是重点我就简单的贴一下代码。也就当作是为了回顾一下android的一些知识吧。
首先我们实现界面的主要布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.cvter.myapplication.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="48dp"
app:tabGravity="fill"
app:tabIndicatorColor="@color/colorAccent"
app:tabMode="fixed"
/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
MainActivity的实现
public class MainActivity extends AppCompatActivity {
private final String NOMALVALUE[] = {"他收藏的帖子","他发表的帖子"};
private ViewPager viewPager;
private TabLayout tabLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
viewPager = (ViewPager)findViewById(R.id.viewPager);
tabLayout = (TabLayout)findViewById(R.id.tabLayout);
BookInfoViewPagerAdapter bookInfoViewPagerAdapter = new BookInfoViewPagerAdapter(getSupportFragmentManager(),NOMALVALUE);
viewPager.setOffscreenPageLimit(2);
viewPager.setAdapter(bookInfoViewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setTabsFromPagerAdapter(bookInfoViewPagerAdapter);
}
class BookInfoViewPagerAdapter extends FragmentPagerAdapter {
private String userValue[];
public BookInfoViewPagerAdapter(FragmentManager fm, String[] userValue) {
super(fm);
this.userValue = userValue;
}
@Override
public Fragment getItem(int position) {
if (position == 0) {
return BookListFragment.getInstance(Database.NEW_BOOKS);
} else {
return BookListFragment.getInstance(Database.ALL_BOOKS);
}
}
@Override
public int getCount() {
return userValue.length;
}
@Override
public CharSequence getPageTitle(int position) {
return userValue[position];
}
}
}
再来是BookListFragment的实现
public class BookListFragment extends Fragment {
private static BookListFragment bookListFragment;
private ListView list;
public static BookListFragment getInstance(ArrayList<Book> books) {
bookListFragment = new BookListFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("booklist",books);
bookListFragment.setArguments(bundle);
return bookListFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_main, container, false);
setupView(view);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayList<Book> books = (ArrayList<Book>) getArguments().getSerializable("booklist");
list.setAdapter(new BooksAdapter(getActivity(), books));
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Book book = (Book) parent.getItemAtPosition(position);
Intent intent = new Intent(getActivity(), BookDetailsActivity.class);
intent.putExtra(BookDetailsActivity.TITLE, book.getTitle());
intent.putExtra(BookDetailsActivity.AUTHOR, book.getAuthor());
startActivity(intent);
}
});
}
private void setupView(View view) {
list = (ListView) (view).findViewById(R.id.list);
}
}
实现的效果图:
解决方法
那么我们按照之前的测试代码看看运行的结果是什么样的
onData(withBookTitle(BOOK_TITLE)).perform(click());
android.support.test.espresso.AmbiguousViewMatcherException: ‘is assignable from class: class android.widget.AdapterView’ matches multiple views in the hierarchy.
Problem views are marked with ‘*MATCHES*’ below.
确实是这样子的。这个时候我们就需要依赖于inAdapterView() 我们看看inAdapterView
/**
* Selects a particular adapter view to operate on, by default we operate on any adapter view
* on the screen.
*/
public DataInteraction inAdapterView(Matcher<View> adapterMatcher) {
this.adapterMatcher = checkNotNull(adapterMatcher);
return this;
}
上面解释已经很清楚了。可以选择指定一个 adapter view 去操作,默认情况下 Espresso 可以操作任何 adapter view。
下来修改我们的测试代码
onData(withBookTitle("Effective Java ")).inAdapterView(allOf(isAssignableFrom(AdapterView.class),isDisplayed())).perform(click());
或者
onData(withBookTitle("Effective Java ")).inAdapterView(allOf(withId(R.id.list),isDisplayed())).perform(click());
都是可以的。
结束语
这章其实更多的还是练手。遇到各种问题的解决。其实还有其他的方法来解决上述的问题的。多动手。。