Espresso 测试框架 - AdapterView

AdapterView 是一种特殊的视图,专门用于呈现使用 Adapter 从底层数据源获取的类似信息集合,例如产品列表和用户联系人。数据源可能是简单列表,也可能是复杂的数据库条目。从 AdapterView 派生的一些视图是 ListViewGridViewSpinner

AdapterView 根据底层数据源中可用的数据量动态呈现用户界面。此外,AdapterView 仅呈现最少的必要数据,这些数据可在屏幕的可用可见区域中呈现。 AdapterView 这样做是为了节省内存,即使底层数据很大,也能使用户界面看起来流畅。

经过分析,AdapterView 架构的性质使 onView 选项及其视图匹配器变得无关紧要,因为要测试的特定视图可能根本不会呈现。幸运的是,espresso 提供了一种方法 onData(,它接受 hamcrest 匹配器(与底层数据的数据类型相关)来匹配底层数据,并返回与匹配数据的视图相对应的 DataInteraction 类型的对象。示例代码如下,

onData(allOf(is(instanceOf(String.class)), startsWith("Apple"))).perform(click())

此处,onData() 匹配条目"Apple",如果它在底层数据(数组列表)中可用,并返回 DataInteraction 对象以与匹配的视图(对应于"Apple"条目的 TextView)进行交互。

方法

DataInteraction 提供以下方法与视图交互,

perform()

它接受视图操作并触发传入的视图操作。

onData(allOf(is(instanceOf(String.class)), startsWith("Apple"))).perform(click())

check()

这接受视图断言并检查传入的视图断言。

onData(allOf(is(instanceOf(String.class)), startsWith("Apple")))
.check(matches(withText("Apple")))

inAdapterView()

这接受视图匹配器。它根据传入的视图匹配器选择特定的 AdapterView 并返回 DataInteraction 对象以与匹配的 AdapterView

进行交互
onData(allOf())
   .inAdapterView(withId(R.id.adapter_view))
   .atPosition(5)
   .perform(click())

atPosition()

这接受一个整型参数,并引用项目在底层数据中的位置。它选择与传入的数据位置值相对应的视图,并返回 DataInteraction 对象以与匹配的视图进行交互。如果我们知道底层数据的正确顺序,它将很有用。

onData(allOf())
    .inAdapterView(withId(R.id.adapter_view))
    .atPosition(5)
    .perform(click())

onChildView()

这接受视图匹配器并匹配特定子视图内的视图。例如,我们可以与基于 AdapterView 的产品列表中的特定项目(如 Buy 按钮)进行交互。

onData(allOf(is(instanceOf(String.class)), startsWith("Apple")))
   .onChildView(withId(R.id.buy_button))
   .perform(click())

编写示例应用程序

按照下面显示的步骤编写一个基于 AdapterView 的简单应用程序,并使用 onData() 方法编写测试用例。

  • 启动 Android Studio。

  • 按照前面讨论的方式创建新项目并将其命名为 MyFruitApp

  • 使用 RefactorMigrateAndroidX 选项菜单将应用程序迁移到 AndroidX 框架。

  • 删除主活动中的默认设计并添加 ListViewactivity_main.xml 的内容如下,

<?xml version = "1.0" encoding = "utf-8"?>
<RelativeLayout 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"
   tools:context = ".MainActivity">
   <ListView
      android:id = "@+id/listView"
      android:layout_width = "wrap_content"
      android:layout_height = "wrap_content" />
</RelativeLayout>
  • 添加新的布局资源item.xml,用于指定列表视图的item模板,item.xml内容如下,

<?xml version = "1.0" encoding = "utf-8"?>
<TextView xmlns:android = "http://schemas.android.com/apk/res/android"
   android:id = "@+id/name"
   android:layout_width = "fill_parent"
   android:layout_height = "fill_parent"
   android:padding = "8dp"
/>
  • 现在,创建一个以水果数组作为基础数据的适配器并将其设置为列表视图。这需要在 MainActivityonCreate() 中完成,如下所示,

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   
   // Find fruit list view
   final ListView listView = (ListView) findViewById(R.id.listView);
   
   // Initialize fruit data
   String[] fruits = new String[]{
      "Apple", 
      "Banana", 
      "Cherry", 
      "Dates", 
      "Elderberry", 
      "Fig", 
      "Grapes", 
      "Grapefruit", 
      "Guava",
      "Jack fruit", 
      "Lemon",
      "Mango", 
      "Orange", 
      "Papaya", 
      "Pears", 
      "Peaches", 
      "Pineapple",
      "Plums", 
      "Raspberry",
      "Strawberry", 
      "Watermelon"
   };
   
   // 创建水果数组列表
   final ArrayList<String> fruitList = new ArrayList<String>();
   for (int i = 0; i < fruits.length; ++i) {
      fruitList.add(fruits[i]);
   }
   
   // 创建数组适配器
   final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item, fruitList);
   
   // 在列表视图中设置适配器
   listView.setAdapter(adapter);
}
  • 现在,编译代码并运行应用程序。My Fruit App 的屏幕截图如下,

Compile The Code
  • 现在,打开 ExampleInstrumentedTest.java 文件并添加 ActivityTestRule,如下所示,

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

另外,请确保测试配置在 app/build.gradle 中完成 −

dependencies {
   testImplementation 'junit:junit:4.12'
   androidTestImplementation 'androidx.test:runner:1.1.1'
   androidTestImplementation 'androidx.test:rules:1.1.1'
   androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
  • 添加一个新的测试用例来测试列表视图,如下所示

@Test
public void listView_isCorrect() {
   // 检查列表视图是否可见
   onView(withId(R.id.listView)).check(matches(isDisplayed()));
   onData(allOf(is(instanceOf(String.class)), startsWith("Apple"))).perform(click());
   onData(allOf(is(instanceOf(String.class)), startsWith("Apple")))
      .check(matches(withText("Apple")));
   // 单击子项
   onData(allOf())
      .inAdapterView(withId(R.id.listView))
      .atPosition(10)
      .perform(click());
}
  • 最后,使用 android studio 的上下文菜单运行测试用例并检查所有测试用例是否成功。