android初学者
本文的重点 (Takeaway From This Article)
In this article, you’ll learn how to use Espresso to find views in the layout based on properties like id
, text
, and more. Then you’ll learn how to check view behavior like visibility and to perform actions like click
. This article also includes how to perform tests on RecyclerView
.
在本文中,您将学习如何使用Espresso基于id
, text
等属性来在布局中查找视图。 然后,您将学习如何检查视图行为(如可见性)和执行诸如click
。 本文还包括如何在RecyclerView
上执行测试。
介绍 (Introduction)
No matter what platform you’re working on, testing gets complicated as the product evolves. For that reason, it’s preferable to use testing frameworks like Espresso to make the process reliable, easy, and effective. Espresso is a testing framework from the Android team to make developers’ lives easy when implementing test cases. It acts as an abstract layer over unit tests and makes it easy to write reliable Android UI tests. Without any further delay, let’s get started.
无论您使用哪种平台,随着产品的发展,测试都会变得复杂。 因此,最好使用诸如Espresso之类的测试框架来使该过程可靠,容易且有效。 Espresso是Android团队的测试框架,可在实施测试用例时简化开发人员的工作。 它充当单元测试的抽象层,使编写可靠的Android UI测试变得容易。 不用再拖延了,让我们开始吧。
When we create an Android project, under the Java directory, you’ll find three subdirectories with application package names.
当我们在Java目录下创建一个Android项目时,您会发现三个带有应用程序包名称的子目录。
- The first directory is to write the application source code. 第一个目录是编写应用程序源代码。
- The second directory is to write Android test cases, as we do in this article with Espresso. 第二个目录是编写Android测试用例,就像我们在本文中对Espresso所做的那样。
- The third directory is for unit test cases. 第三个目录用于单元测试用例。
积分 (Integration)
These days, when you create a new project in Android Studio, Espresso is integrated by default. If you removed those libraries in the existing project or if you don’t see the Espresso implementation library under the dependency tag, add the following lines.
如今,当您在Android Studio中创建新项目时,默认情况下会集成Espresso。 如果您在现有项目中删除了这些库,或者在dependency标签下看不到Espresso实现库,请添加以下行。
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
组件 (Components)
Espresso has basically three components:
浓缩咖啡基本上具有三个组成部分:
viewMatcher
s: allows you to find a view in the current view hierarchy through various parameters likeid
,text
, and moreviewMatcher
s:允许您通过各种参数(例如id
,text
等)在当前视图层次结构中查找视图viewAction
s: allows you to perform actions on the views likeclick
and moreviewAction
: 允许您对视图执行操作,例如click
和更多viewAssertion
s: allows you to assert the state of a viewviewAssertion
s:允许您声明视图的状态
Have a look at the generic usage of these components.
看一下这些组件的一般用法。
onView(viewmatcher)
.check(viewAction)
.perform(viewAssertion)
onView (onView)
Using this function, we can narrow down to the desired view in the view hierarchy. It can be done by using the following functions inside onview
:
使用此功能,我们可以缩小视图层次结构中的所需视图。 可以通过在onview
使用以下功能来完成:
withId(
— With this function, we can narrow down the view search using ids of the view.withId(
—使用此功能,我们可以使用视图的ID缩小视图搜索范围。withText()
— Here we can pass the desired text to narrow down the views based on the text.withText()
—在这里,我们可以传递所需的文本以根据文本缩小视图范围。
检查 (check)
This is used to check the behavior of the desired view, like visibility, focus, and more using matches
and doesNotExist
.
这是用来检查所期望的视图的行为,如能见度,聚焦,和更多的应用matches
和doesNotExist
。
执行 (perform)
Through perform
, we can execute actions on the views. Following are some of the actions that we can execute using Espresso:
通过perform
,我们可以对视图执行操作。 以下是我们可以使用Espresso执行的一些操作:
click()
— Clicks the view passed inonView
click()
—click()
在onView
传递的视图typeText()
— Through this function, we can pass the string to be entered in the view. This comes handy withEditText
.typeText()
—通过此函数,我们可以传递要在视图中输入的字符串。EditText
可以很方便地使用它。replaceText()
— Replaces the current text with the string that’s passedreplaceText()
—用传递的字符串替换当前文本closeSoftKeyboard()
— Dismisses the keyboardcloseSoftKeyboard()
-closeSoftKeyboard()
键盘
用法 (Usage)
Let’s say we have an application with an activity and its layout contains a view with id tv_hello
. Our goal here is to find whether the view with the id tv_hello
is displayed on the screen. Have a look:
假设我们有一个带有活动的应用程序,其布局包含一个ID为tv_hello
的视图。 我们的目标是确定是否在屏幕上显示ID为tv_hello
的视图。 看一看:
@Test
fun simpleDisplyTest(){
onView(withId(R.id.tv_hello))
.check(isDisplayed())
}
First, it’ll start searching a view with id tv_hello
, and once it found the view using check
function, it’ll verify the visibility through isDisplayed()
.
首先,它将开始搜索ID为tv_hello
的视图,并使用check
功能找到该视图后,将通过isDisplayed()
验证可见性。
We can also use multiple constraints to narrow down the view search, as shown below:
我们还可以使用多个约束来缩小视图搜索范围,如下所示:
@Test
fun multipleConstraintsTest(){
onView(allOf(withId(R.id.tv_hello),
withText("Hello World!")))
.check(matches(isDisplayed()))
}
In this test, while searching for a view, it will consider two constraints: withId
(with a specific id) and withText
(with a specific text in the view).
在此测试中,在搜索视图时,它将考虑两个约束: withId
(具有特定的id)和withText
(具有视图中的特定文本)。
动作 (Actions)
Now it’s time to perform actions on the narrowed views. To execute actions, we have to invoke a perform-function on onView
with the desired action, as shown below:
现在是时候对缩小的视图执行操作了。 要执行动作,我们必须使用所需的动作在onView
上调用性能函数,如下所示:
@Test
fun simpleClickTest(){
onView(withId(R.id.btn_click))
.check(matches(isDisplayed()))
.perform(click())
}
We can also pass multiple actions as parameters to the perform
function, as shown below:
我们还可以将多个动作作为参数传递给perform
函数,如下所示:
@Test
fun multipleActionsTest(){
onView(withId(R.id.btn_click))
.check(matches(isDisplayed()))
.perform(typeText("Hello"),click()
}
In this test first, it’ll type “Hello” on the view and then perform the click
action. Only if both actions are executed without any error will the test succeed.
首先在此测试中,它将在视图上键入“ Hello”,然后执行click
操作。 只有同时执行两个操作而没有任何错误,测试才能成功。
清单 (Lists)
We’ve completed basic testing with the standard layout. What if we have complicated views, like a list? To write test cases on lists, we have another function called onData
, similar to onView
.
我们已经使用标准布局完成了基本测试。 如果我们有复杂的视图(例如列表)怎么办? 为了在列表上编写测试用例,我们还有另一个函数onData
,类似于onView
。
Let’s say we have a list with a string ArrayList
, and we need to find the item with text Kotlin
and perform click
functionality on that particular item. Have a look:
假设我们有一个包含字符串ArrayList
的列表,我们需要找到带有文本Kotlin
的项目并对该特定项目执行click
功能。 看一看:
onData(withItemContent("Kotlin"))
.perform(click())
In a real-time scenario, things won’t be simple like this. Let’s say we have a listview-item
with multiple clicks, and we need to test click
functionality of a view with id edit
in the item with content Kotlin
. Have a look:
在实时场景中,事情不会像这样简单。 假设我们有一个带有多次单击的listview-item
,我们需要在内容为Kotlin
的项目中测试ID为edit
的视图的click
功能。 看一看:
onData(withItemContent("Kotlin"))
.onChildView(withId(R.id.edit))
.perform(click())
带有Espresso的RecyclerView (RecyclerView with Espresso)
RecyclerView
objects behave differently than AdapterView
objects; we can’t use onData()
to test RecyclerView
.
RecyclerView
对象的行为与AdapterView
对象不同。 我们不能使用onData()
测试RecyclerView
。
To create an interaction between RecyclerView
and Espresso, we need to add the espresso-contrib
module, which has RecyclerViewActions
to perform actions like click
, scrollTo
, and more useful stuff.
要在RecyclerView
和Espresso之间创建交互,我们需要添加espresso-contrib
模块,该模块具有RecyclerViewActions
来执行诸如click
, scrollTo
和其他更有用的操作。
积分 (Integration)
To integrate the espresso-contrib
module, add the following line under the dependency node in the app level build.gradle
file.
要集成espresso-contrib
模块,请在应用程序级别build.gradle
文件的依赖项节点下添加以下行。
dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.2.0'
}
RecyclerViewActions (RecyclerViewActions)
scrollTo
: Scrolls theRecyclerView
to matched itemscrollTo
:将RecyclerView
滚动到匹配的项目scrollToHolder
: This is used to scroll theRecyclerView
to a matched view holder.scrollToHolder
:用于将RecyclerView
滚动到匹配的视图持有者。scrollToPosition
: This is used to scroll theRecyclerView
to the mentioned position, and if it doesn’t have that position, the test will fail.scrollToPosition
:用于将RecyclerView
滚动到提到的位置,如果没有该位置,则测试将失败。actionOnHolderItem
: ThisRecyclerViewAction
performs aViewAction
on a matched view holder.actionOnHolderItem
:此RecyclerViewAction
在匹配的视图持有者上执行ViewAction
。actionOnItem
: ThisRecyclerViewAction
performs aViewAction
on a matched view.actionOnItem
:此RecyclerViewAction
对匹配的视图执行ViewAction
。actionOnItemAtPosition
: ThisRecyclerViewAction
performs aViewAction
on a view at a specific position.actionOnItemAtPosition
:此RecyclerViewAction
在特定位置的视图上执行ViewAction
。
用法 (Usage)
The first step to work with RecyclerView
is to find RecyclerView
using onView
function and the id
of RecyclerView
, as shown below:
第一步与工作RecyclerView
是找到RecyclerView
使用onView
功能和id
的RecyclerView
,如下图所示:
onView(ViewMatchers.withId(R.id.recycler_view))
Let’s start with a simple scroll test. Our object here is to scroll the RecyclerView
to a specific position. To do that, we use scrollToPosition
on recyclerviewAction
, as shown below:
让我们从一个简单的滚动测试开始。 我们的目的是将RecyclerView
滚动到特定位置。 为此,我们使用scrollToPosition
在recyclerviewAction
,如下所示:
@Test
fun scrollTopositionTest(){
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.scrollToPosition<NewsViewHolder>(17))
}
To explore a bit more, let’s write a test where our objective is to click
the item with content Kotlin
. Have a look:
要进一步探索,让我们编写一个测试,我们的目标是click
内容为Kotlin
的项目。 看一看:
@Test
fun clickItemtWithPosition(){
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.actionOnItem<NewsViewHolder>(
hasDescendant(withText("Kotlin")),
click()))
}
Here hasDescendant
function is the key. It’ll check the descendant views of every item in the list, and if it gets a match, then it’ll perform the click
action.
这里hasDescendant
函数是关键。 它将检查列表中每个项目的后代视图,如果找到匹配项,则将执行click
动作。
在RecyclerView中单击项目级别视图 (Item level view-clicks in RecyclerView)
Unfortunately, there is no direct function out of the box to test the inner view clicks of the RecyclerView
item. To achieve this, first we need to create a custom action that extends ViewAction
, as shown below:
不幸的是,没有开箱即用的直接功能来测试RecyclerView
项的内部视图点击。 为此,首先我们需要创建一个扩展ViewAction
的自定义动作,如下所示:
fun clickChildViewWithId(id: Int): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View>? {
return null
}
override fun getDescription(): String {
return "Click on a child view with specific id."
}
override fun perform(
uiController: UiController,
view: View
) {
val v = view.findViewById<View>(id)
v.performClick()
}
}
}
Now using the above custom, we can perform item-level view clicks, as shown below:
现在,使用上面的自定义,我们可以执行项目级视图点击,如下所示:
@Test
fun customActionTestRecyclerview(){
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.actionOnItemAtPosition<NewsViewHolder>(17,
clickChildViewWithId(R.id.date_category_text_view)))
}
That’s all. I hope you learned something useful. Thanks for reading.
就这样。 我希望你学到了一些有用的东西。 谢谢阅读。
翻译自: https://medium.com/better-programming/android-espresso-for-beginners-57628a15f8b4
android初学者