不错的官方文档翻译(含作者见解)
这篇文章翻译简直太棒了,本文的内容都来自对该文章所记录的笔记。
Android自动化测试--Espresso框架使用
Android官网,_科学上网也访问不了跪求原因

如何使用Espresso

  1. 在module级别的Gradle中添加以下配置
android {    defaultConfig {        ...        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"    }}

2.添加依赖

dependencies {    androidTestCompile 'com.android.support:support-annotations:23.1.1'    androidTestCompile 'com.android.support.test:runner:0.4.1'    androidTestCompile 'com.android.support.test:rules:0.4.1'    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'}

3.测试代码编写
一般来说我们在main/java中放置主要的业务逻辑代码,在 androidTest/java放置测试代码.

src/    androidTest/java    ----这里存放instrumentation test相关的代码    main/java           ----这里存放工程代码

建议测试代码的分类与被测试类放置在相同的包目录下,例如待测试的类为src/main/java/package-name/A.java,那么测试类可以放置在src/androidTest/java/package-name/ATest.java目录下,测试类名称以Test作为后缀.

Espresso的一些语法

onView() 查找元素,其完整的方法签名如下:

public static ViewInteraction onView(final Matcher viewMatcher) {}

这个方法接收一个Matcher类型的入参,返回一个ViewInteraction对象,其所做的事情就是根据Matcher所指定的条件,在当前UI页面上寻找符合条件的View,并且把相应的View返回出来。这样说还是比较抽象,我们可以用一个具体的例子加以说明。

当我们在实现布局的时候,每个控件都会有一些特殊的属性来确定其唯一性,比如最常用的R.id。Matcher支持通过控件的唯一ID来从当前页面上寻找目标控件,对应的方法为withId(),该方法定义如下:

public static Matcher withId(final int id) {}

大家可以看到,该方法接收了一个int类型的入参,返回了一个Matcher对象,于是,采用如下写法:

onView(withId(id));

我们就能在当前页面找到指定ID所对应的目标控件了。

实际上,Espresso提供了很多方法来让我们自定义我们的查找条件。比如我们可以通过withText()方法来寻找显示了指定文案的控件等等。具体支持的Matcher类型可以参考Espresso cheat sheet。

需要提醒大家一点的是,onView()方法在根据匹配条件进行查找时,它的目标是找到唯一的一个目标控件。如果我们制定的匹配条件有多个控件可以匹配(比如复用了layout的布局,或者显示相同文字的TextView等),该方法会抛出一个AmbiguousViewMatcherException异常,因此我们在构造匹配条件时,一定要确保能查找到的目标控件是唯一的。

如果单一的匹配条件无法精确地匹配出来唯一的控件,我们可能还需要额外的匹配条件,此时可以用allOf()方法来进行复合匹配条件的构造:

onView(allOf(withId(id), withText(text)))

以上代码可以查找ID为id同时显示的文字内容为text的控件。这里需要注意的是,为了保证自动化测试的效率,我们应尽可能减少匹配条件的数量。如果用一个匹配条件能够满足我们的需求,我们也就没有必要再用allOf()来构造复合匹配条件了。

操作元素

public ViewInteraction perform(final ViewAction... viewActions) {}

该方法定义在ViewInteraction类里面。还记得onView()方法的返回值么?yes,正是一个ViewInteraction对象。因此,我们可以在onView()方法找到的元素上直接调用perform()方法进行一系列操作:

onView(withId(id)).perform(click())

如上代码对onView()查询到的元素做了一次点击的操作。请注意,perform()方法的入参是变长参数,也就意味着,我们可以依次对某个元素做多个操作:

onView(withId(id)).perform(click(), replaceText(text), closeSoftKeyboard())

以上代码对目标元素依次做了点击、输入文本、关闭输入法键盘的操作。这是一个典型的填写表单的行为。

检查结果

到目前为止,我们已经能找到元素,也能够对元素进行一些操作了!接下来我们需要检查一下这些操作的结果是否符合我们的预期。

Espresso提供了一个check()方法用来检测结果:

public ViewInteraction check(final ViewAssertion viewAssert) {}

该方法接收了一个ViewAssertion的入参,该入参的作用就是检查结果是否符合我们的预期。一般来说,我们可以调用如下的方法来自定义一个ViewAssertion:

public static ViewAssertion matches(final Matcher<? super View> viewMatcher) {}

这个方法接收了一个匹配规则,然后根据这个规则为我们生成了一个ViewAssertion对象!还记得Matcher这个类型么!!是的,这就是onView()方法的入参!实际上他们是同一个类型,其使用方法也是完全一致的。

比如,我想检查一下指定id的TextView是否按照我的预期显示了一段text文本,那么我就可以这样写:

onView(withId(id)).check(matches(withText(text)))

简洁明了。ViewAssertion的支持也可以参照这个Espresso cheat sheet。

AdapterView

对于类似ListView这种有UI复用的元素来说,只是通过onView()就显得复杂了一点,我们来看一下针对这种情况应有何种方案。

AdapterView是一种通过Adapter来动态加载数据的界面元素。我们常用的ListView, GridView, Spinner等等都属于AdapterView。不同于我们之前提到的静态的控件,AdapterView在加载数据时,可能只有一部分显示在了屏幕上,对于没有显示在屏幕上的那部分数据,我们通过onView()是没有办法找到的。

对于AdapterView,Espresso提供了如下方法用来查找元素:

/** * Creates an {@link DataInteraction} for a data object displayed by the application. Use this * method to load (into the view hierarchy) items from AdapterView widgets (e.g. ListView). * * @param dataMatcher a matcher used to find the data object. */public static DataInteraction onData(Matcher<? extends Object> dataMatcher) {}

我们首先来研究一下这个方法的返回值。从以上定义可以看出,该方法返回了一个DataInteraction对象,还记得onView()方法返回的ViewInteraction对象么?这两者的区别可以大概描述为:

  • ViewInteraction: 关注于已经匹配到的目标控件。通过onView()方法我们可以找到符合匹配条件的唯一的目标控件,我们只需要针对这个控件进行我们需要的操作。
  • DataInteraction: 关注于AdapterView的数据。由于AdapterView的数据源可能很长,很多时候无法一次性将所有数据源显示在屏幕上,因此我们主要先关注AdapterView中包含的数据,而非一次性就进行View的匹配。

我们再来研究一下这个方法的入参。从以上定义看出,该方法接收了一个Matcher<? extends Object>的参数,该参数用来指定一个匹配规则。还记得onView()的入参么?是一个Matcher对象。从类型上来看,这两者的区别也不言而喻:

  • Matcher: 构造一个针对于View匹配的匹配规则;
  • Matcher<? extends Object>: 构造一个针对于Object(数据)匹配的匹配规则。

从以上对比可以看出,我们在使用onData()方法对AdapterView进行测试的时候,我们的思路就转变成了首先关注这个AdapterView的具体数据,而不是UI上呈现的内容。当然,我们最终的目标还是要找到目标的UI元素,但是我们是通过其数据源来进行入手的。

寻找数据

那么,接下来,我们就要学习如何去寻找我们需要的数据了!显然,要想找到我们需要的数据,就需要构造一个onData()所使用的Matcher对象,而这个对象的构造和使用实际上和之前我们所用的针对于View的Matcher大概雷同。比如,我们可以指定单一条件:

onData(is(instanceOf(MyObject.class)))

表示我们需要找一个AdapterView,其数据源的类型是MyObject(这是一个自定义的类)。当然了,我们肯定还是需要更加精确地去寻找一个AdapterView中的指定条目,于是我们可以采用allOf()来构造一个符合匹配条件:

onData(allOf(is(instanceOf(MyObject.class)), myCustomMatcher()))

如上代码便使用allOf()方法构造了一个符合匹配规则。而上面的myCustomMatcher()方法构造了一个自定义的Matcher,我们可以采用自己的自定义Matcher来更加精准地进行数据的匹配。

//TODO

自定义Matcher

更多相关文章

  1. android adt安装成功后 eclipse菜单栏没有相应的图标的解决方法
  2. Android Chronometer控件实现计时器函数详解
  3. 【Android 初学】5、控件--ImageView的使用方法
  4. [置顶] 我的Android进阶之旅------>Ubuntu下不能识别Android设备
  5. Android-Jni线程(三)— JNI全局回调java方法
  6. Android基础--------Android常用控件介绍及使用

随机推荐

  1. Android TextView使用及性能优化
  2. 关于设置android:imeOptions属性无效的解
  3. android:layout_alignParent 布局相对于
  4. Android高手进阶教程(十一)--Android 通
  5. Windows下安装Android SDK与USB驱动程序
  6. Android推送方式比较
  7. Android 新闻客户端案例
  8. android消息推送-XMPP
  9. Android 学习笔记 —— Android 四大组件
  10. Suggestion: add 'tools:replace="androi