- Espresso 测试框架教程
- Espresso 测试 - 首页
- 简介
- 设置说明
- 在 Android Studio 中运行测试
- JUnit 概述
- 架构
- 视图匹配器
- 自定义视图匹配器
- 视图断言
- 视图操作
- 测试 AdapterView
- 测试 WebView
- 测试异步操作
- 测试 Intent
- 测试多个应用程序的 UI
- 测试录制器
- 测试 UI 性能
- 测试可访问性
- Espresso 测试资源
- Espresso 测试 - 快速指南
- Espresso 测试 - 有用资源
- Espresso 测试 - 讨论
Espresso 测试框架 - 视图匹配器
Espresso 框架提供了许多视图匹配器。匹配器的目的是使用视图的不同属性(例如 Id、文本和子视图的可用性)来匹配视图。每个匹配器都匹配视图的特定属性并应用于特定类型的视图。例如,withId 匹配器匹配视图的 Id 属性并应用于所有视图,而 withText 匹配器匹配视图的 Text 属性,仅应用于 TextView。
在本章中,让我们学习 Espresso 测试框架提供的不同匹配器,以及学习 Espresso 匹配器构建的基础库 Hamcrest。
Hamcrest 库
Hamcrest 库在 Espresso 测试框架的范围内是一个重要的库。Hamcrest 本身是一个用于编写匹配器对象的框架。Espresso 框架广泛使用 Hamcrest 库,并在必要时对其进行扩展以提供简单且可扩展的匹配器。
Hamcrest 提供了一个简单的函数 assertThat 和一系列匹配器来断言任何对象。assertThat 有三个参数,如下所示:
字符串(测试描述,可选)
对象(实际值)
匹配器(预期值)
让我们编写一个简单的示例来测试列表对象是否具有预期值。
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
@Test
public void list_hasValue() {
ArrayList<String> list = new ArrayList<String>();
list.add("John");
assertThat("Is list has John?", list, hasItem("John"));
}
这里,hasItem 返回一个匹配器,它检查实际列表是否具有指定值作为其中一项。
Hamcrest 具有许多内置匹配器,以及创建新匹配器的选项。在 Espresso 测试框架中,一些有用的重要内置匹配器如下:
anything - 总是匹配
基于逻辑的匹配器
allOf - 接受任意数量的匹配器,只有当所有匹配器都成功时才匹配。
anyOf - 接受任意数量的匹配器,如果任何一个匹配器成功则匹配。
not - 接受一个匹配器,只有当匹配器失败时才匹配,反之亦然。
基于文本的匹配器
equalToIgnoringCase - 用于测试实际输入是否等于预期字符串(忽略大小写)。
equalToIgnoringWhiteSpace - 用于测试实际输入是否等于指定的字符串(忽略大小写和空格)。
containsString - 用于测试实际输入是否包含指定的字符串。
endsWith - 用于测试实际输入是否以指定的字符串结尾。
startsWith - 用于测试实际输入是否以指定的字符串开头。
基于数字的匹配器
closeTo - 用于测试实际输入是否接近预期数字。
greaterThan - 用于测试实际输入是否大于预期数字。
greaterThanOrEqualTo - 用于测试实际输入是否大于或等于预期数字。
lessThan - 用于测试实际输入是否小于预期数字。
lessThanOrEqualTo - 用于测试实际输入是否小于或等于预期数字。
基于对象的匹配器
equalTo - 用于测试实际输入是否等于预期对象。
hasToString - 用于测试实际输入是否具有 toString 方法。
instanceOf - 用于测试实际输入是否是预期类的实例。
isCompatibleType - 用于测试实际输入是否与预期类型兼容。
notNullValue - 用于测试实际输入是否不为空。
sameInstance - 用于测试实际输入和预期值是否为同一实例。
hasProperty - 用于测试实际输入是否具有预期的属性。
is - equalTo 的简写或语法糖
匹配器
Espresso 提供了 onView() 方法来匹配和查找视图。它接受视图匹配器并返回 ViewInteraction 对象以与匹配的视图交互。常用视图匹配器列表如下:
withId()
withId() 接受一个 int 类型的参数,该参数引用视图的 id。它返回一个匹配器,该匹配器使用视图的 id 来匹配视图。示例代码如下:
onView(withId(R.id.testView))
withText()
withText() 接受一个 string 类型的参数,该参数引用视图的文本属性的值。它返回一个匹配器,该匹配器使用视图的文本值来匹配视图。它仅适用于 TextView。示例代码如下:
onView(withText("Hello World!"))
withContentDescription()
withContentDescription() 接受一个 string 类型的参数,该参数引用视图的内容描述属性的值。它返回一个匹配器,该匹配器使用视图的描述来匹配视图。示例代码如下:
onView(withContentDescription("blah"))
我们还可以传递文本值的资源 ID 而不是文本本身。
onView(withContentDescription(R.id.res_id_blah))
hasContentDescription()
hasContentDescription() 没有参数。它返回一个匹配器,该匹配器匹配具有任何内容描述的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), hasContentDescription()))
withTagKey()
withTagKey() 接受一个 string 类型的参数,该参数引用视图的标签键。它返回一个匹配器,该匹配器使用其标签键来匹配视图。示例代码如下:
onView(withTagKey("blah"))
我们还可以传递标签名称的资源 ID 而不是标签名称本身。
onView(withTagKey(R.id.res_id_blah))
withTagValue()
withTagValue() 接受一个 Matcher 类型的参数,该参数引用视图的标签值。它返回一个匹配器,该匹配器使用其标签值来匹配视图。示例代码如下:
onView(withTagValue(is((Object) "blah")))
这里,is 是 Hamcrest 匹配器。
withClassName()
withClassName() 接受一个 Matcher 类型的参数,该参数引用视图的类名值。它返回一个匹配器,该匹配器使用其类名来匹配视图。示例代码如下:
onView(withClassName(endsWith("EditText")))
这里,endsWith 是 Hamcrest 匹配器并返回 Matcher。
withHint()
withHint() 接受一个 Matcher 类型的参数,该参数引用视图的提示值。它返回一个匹配器,该匹配器使用视图的提示来匹配视图。示例代码如下:
onView(withClassName(endsWith("Enter name")))
withInputType()
withInputType() 接受一个 int 类型的参数,该参数引用视图的输入类型。它返回一个匹配器,该匹配器使用其输入类型来匹配视图。示例代码如下:
onView(withInputType(TYPE_CLASS_DATETIME))
这里,TYPE_CLASS_DATETIME 指的是支持日期和时间的编辑视图。
withResourceName()
withResourceName() 接受一个 Matcher 类型的参数,该参数引用视图的类名值。它返回一个匹配器,该匹配器使用视图的资源名称来匹配视图。示例代码如下:
onView(withResourceName(endsWith("res_name")))
它也接受字符串参数。示例代码如下:
onView(withResourceName("my_res_name"))
withAlpha()
withAlpha() 接受一个 float 类型的参数,该参数引用视图的 alpha 值。它返回一个匹配器,该匹配器使用视图的 alpha 值来匹配视图。示例代码如下:
onView(withAlpha(0.8))
withEffectiveVisibility()
withEffectiveVisibility() 接受一个 ViewMatchers.Visibility 类型的参数,该参数引用视图的有效可见性。它返回一个匹配器,该匹配器使用视图的可见性来匹配视图。示例代码如下:
onView(withEffectiveVisibility(withEffectiveVisibility.INVISIBLE))
withSpinnerText()
withSpinnerText() 接受一个 Matcher 类型的参数,该参数引用 Spinner 当前选定视图的值。它返回一个匹配器,该匹配器根据其选定项目的 toString 值来匹配 Spinner。示例代码如下:
onView(withSpinnerText(endsWith("USA")))
它也接受字符串参数或字符串的资源 ID。示例代码如下:
onView(withResourceName("USA"))
onView(withResourceName(R.string.res_usa))
withSubstring()
withSubString() 与 withText() 类似,不同之处在于它有助于测试视图文本值的子字符串。
onView(withSubString("Hello"))
hasLinks()
hasLinks() 没有参数,它返回一个匹配器,该匹配器匹配具有链接的视图。它仅适用于 TextView。示例代码如下:
onView(allOf(withSubString("Hello"), hasLinks()))
这里,allOf 是一个 Hamcrest 匹配器。allOf 返回一个匹配器,该匹配器匹配所有传入的匹配器,在这里,它用于匹配视图以及检查视图的文本值中是否包含链接。
hasTextColor()
hasTextColor() 接受一个 int 类型的参数,该参数引用颜色的资源 ID。它返回一个匹配器,该匹配器根据其颜色匹配 TextView。它仅适用于 TextView。示例代码如下:
onView(allOf(withSubString("Hello"), hasTextColor(R.color.Red)))
hasEllipsizedText()
hasEllipsizedText() 没有参数。它返回一个匹配器,该匹配器匹配具有长文本且已省略号显示(开头…中间…结尾)或被截断(开头…)的 TextView。示例代码如下:
onView(allOf(withId(R.id.my_text_view_id), hasEllipsizedText()))
hasMultilineText()
hasMultilineText() 没有参数。它返回一个匹配器,该匹配器匹配具有任何多行文本的 TextView。示例代码如下:
onView(allOf(withId(R.id.my_test_view_id), hasMultilineText()))
hasBackground()
hasBackground() 接受一个 int 类型的参数,该参数引用背景资源的资源 ID。它返回一个匹配器,该匹配器根据其背景资源匹配视图。示例代码如下:
onView(allOf(withId("image"), hasBackground(R.drawable.your_drawable)))
hasErrorText()
hasErrorText() 接受一个 Matcher 类型的参数,该参数引用视图(EditText)的错误字符串值。它返回一个匹配器,该匹配器使用视图的错误字符串来匹配视图。这仅适用于 EditText。示例代码如下:
onView(allOf(withId(R.id.editText_name), hasErrorText(is("name is required"))))
它也接受字符串参数。示例代码如下:
onView(allOf(withId(R.id.editText_name), hasErrorText("name is required")))
hasImeAction()
hasImeAction() 接受一个 Matcher 类型的参数,该参数引用视图(EditText)支持的输入方法。它返回一个匹配器,该匹配器使用视图支持的输入方法来匹配视图。这仅适用于 EditText。示例代码如下:
onView(allOf(withId(R.id.editText_name), hasImeAction(is(EditorInfo.IME_ACTION_GO))))
这里,EditorInfo.IME_ACTION_GO 是输入方法选项之一。hasImeAction() 也接受整数参数。示例代码如下:
onView(allOf(withId(R.id.editText_name), hasImeAction(EditorInfo.IME_ACTION_GO)))
supportsInputMethods()
supportsInputMethods() 没有参数。如果视图支持输入方法,它将返回一个匹配该视图的匹配器。示例代码如下:
onView(allOf(withId(R.id.editText_name), supportsInputMethods()))
isRoot()
isRoot() 没有参数。它返回一个匹配根视图的匹配器。示例代码如下:
onView(allOf(withId(R.id.my_root_id), isRoot()))
isDisplayed()
isDisplayed() 没有参数。它返回一个匹配当前显示的视图的匹配器。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isDisplayed()))
isDisplayingAtLeast()
isDisplayingAtLeast() 接受一个 int 类型的参数。它返回一个匹配器,该匹配器匹配当前至少显示指定百分比的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isDisplayingAtLeast(75)))
isCompletelyDisplayed()
isCompletelyDisplayed() 没有参数。它返回一个匹配器,该匹配器匹配当前完全显示在屏幕上的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isCompletelyDisplayed()))
isEnabled()
isEnabled() 没有参数。它返回一个匹配已启用视图的匹配器。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isEnabled()))
isFocusable()
isFocusable() 没有参数。它返回一个匹配具有焦点选项的视图的匹配器。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isFocusable()))
hasFocus()
hasFocus() 没有参数。它返回一个匹配器,匹配当前获得焦点的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), hasFocus()))
isClickable()
isClickable() 没有参数。它返回一个匹配器,匹配具有点击选项的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isClickable()))
isSelected()
isSelected() 没有参数。它返回一个匹配器,匹配当前选中的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isSelected()))
isChecked()
isChecked() 没有参数。它返回一个匹配器,匹配类型为CompoundButton(或其子类型)且处于选中状态的视图。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isChecked()))
isNotChecked()
isNotChecked() 与isChecked正好相反。示例代码如下:
onView(allOf(withId(R.id.my_view_id), isNotChecked()))
isJavascriptEnabled()
isJavascriptEnabled() 没有参数。它返回一个匹配器,匹配正在执行JavaScript的WebView。示例代码如下:
onView(allOf(withId(R.id.my_webview_id), isJavascriptEnabled()))
withParent()
withParent() 接受一个类型为Matcher<View>的参数。该参数指的是一个视图。它返回一个匹配器,匹配指定视图作为父视图的视图。示例代码如下:
onView(allOf(withId(R.id.childView), withParent(withId(R.id.parentView))))
hasSibling()
hasSibling() 接受一个类型为Matcher<View>的参数。该参数指的是一个视图。它返回一个匹配器,匹配传入视图是其兄弟视图之一的视图。示例代码如下:
onView(hasSibling(withId(R.id.siblingView)))
withChild()
withChild() 接受一个类型为Matcher<View>的参数。该参数指的是一个视图。它返回一个匹配器,匹配传入视图是子视图的视图。示例代码如下:
onView(allOf(withId(R.id.parentView), withChild(withId(R.id.childView))))
hasChildCount()
hasChildCount() 接受一个类型为int的参数。该参数指的是视图的子视图数量。它返回一个匹配器,匹配子视图数量与参数中指定的数量完全相同的视图。示例代码如下:
onView(hasChildCount(4))
hasMinimumChildCount()
hasMinimumChildCount() 接受一个类型为int的参数。该参数指的是视图的子视图数量。它返回一个匹配器,匹配子视图数量至少与参数中指定的数量相同的视图。示例代码如下:
onView(hasMinimumChildCount(4))
hasDescendant()
hasDescendant() 接受一个类型为Matcher<View>的参数。该参数指的是一个视图。它返回一个匹配器,匹配传入视图是视图层次结构中某个后代视图的视图。示例代码如下:
onView(hasDescendant(withId(R.id.descendantView)))
isDescendantOfA()
isDescendantOfA() 接受一个类型为Matcher<View>的参数。该参数指的是一个视图。它返回一个匹配器,匹配传入视图是视图层次结构中某个祖先视图的视图。示例代码如下:
onView(allOf(withId(R.id.myView), isDescendantOfA(withId(R.id.parentView))))