Espresso 基础

前言

自动化测试就是根据用用户使用过程中可能做的交互,进行预先模拟。Espresso 框架不允许使用类似findviewByid( )对应用程序活动和视图的进行直接访问,所以在Espresso API中 不会直接看到类似getView和getCurrentActivity的方法。但是可以通过其他方式安全地实现匹配元素。

Espresso 单元测试demo 效果

视频地址:http://pan.baidu.com/s/1jH4Ldd0

Espresso的主要组件概述:

Espresso -入口点交互通过onView()和onData()。

ViewActions -集合ViewAction中的可以执行模拟事件,通过perform()方法(例如,click())。
ViewAssertions -对象ViewAssertion中的可传递的ViewInteraction.check()方法。大多数时候,使用matches断言,是否符合预期,它使用View匹配器来断言当前选择的视图的状态。(是否显示在界面,是否可点击,是否符合预期等)
ViewMatchers -实现对象的集合Matcher接口。可以通过一个或多个Matcher规则来定位当前视图层级中的图。

Example:

onView(withId(R.id.my_view))      // withId(R.id.my_view) is a ViewMatcher
  .perform(click())               // click() is a ViewAction
  .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion

使用onView查找视图

在绝大多数情况下,onView方法需要配合使用一个hamcrest匹配器框架,该匹配器匹配当前视图层次结构中的一个(且只有一个)视图。Matchers是强大的,与Mockito或Junit 的匹配规则很相似。如果你不熟悉hamcrest的匹配,我们建议您先快速浏览一下


Blog这个演示:http://www.slideshare.net/shaiyallin/hamcrest-matchers 或者查看测试脚本android_testing

通常情况下,所需匹配的视图具有独特的R.id和简单的withId匹配将缩小视图搜索。不过,也有当你无法判断许多合法的情况下,R.id在测试开发时间。例如,特定视图可能不具有R.id或R.id不是唯一的。这可以使 instrumentation tests 来进行测试,因为findViewById()的方式来访问预览是不工作的。因此,您可能需要访问持有视图的Activity或Fragment的私有成员,或者找到具有已知R.id的容器,并导航到特定视图的内容。
Espresso 允许你使用ViewMatchers缩小或者使用其它方式(自定义视图匹配器)进行缩小视图层次范围,达到最终定位视图层次中的视图。

//通过其R.id查找视图非常简单:

onView(withId(R.id.my_view))

有时,在多个视图之间共享R.id值。当发生这种情况的尝试以使用特定的R.id给你一个AmbiguousViewMatcherException(例如)。异常消息为您提供了当前视图层次,你可以搜索并找到,非唯一异常的文本表示:

java.lang.RuntimeException:com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException:This matcher matches multiple views in the hierarchy: (withId: is <123456789>)
... ...
+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true,
is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true,
is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}****MATCHES****

通过查看视图的各种属性,您可能会发现唯一可识别的属性(在上面的示例中,其中一个视图具有文本“Hello!”)。您可以使用此方法通过使用组合匹配器缩小搜索范围:

onView(allOf(withId(R.id.my_view), withText("Hello!"))) allof(指定两者都符合)
您还可以使用not扭转任何匹配器:
onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))))

见ViewMatchers由Espresso提供的视图的匹配。

这里写图片描述

注意:在运行良好的应用程序,所有视图,用户都应包含说明性文字或有内容描述(见Android的易用性原则如果您在使用OnView 的“withText’或’ withContentDescription’ 无法缩小搜索。考虑将它作为一个可访问性的bug。
注意:用最少的描述匹配去寻找。不要过度指定匹配条件,因为这将迫使框架做比必要的更多的工作。例如,如果一个视图是由它的文本唯一标识,则不需要指定R.id.myid 来进行匹配,WithText( “ 文本唯一”),可以完成大部分的匹配
注意:如果目标视图在AdapterView(例如ListView,GridView,Spinner)的内部,onView方法可能无法正常工作,并建议使用onData方法来代替。
对视图执行操作
当找到了目标视图的适当匹配,则能够进行ViewAction利用上perform的方法。
例如,点击视图:

onView(...).perform(click());

您可以使用一个执行调用执行多个操作:

onView(...).perform(typeText("Hello"), click());

如果你正在使用的视图位于内ScrollView(垂直或水平),考虑上述要求需要提前进行显示(如视图操作click()和typeText())用scrollTo()。这确保在继续执行其他操作之前显示视图:

onView(...).perform(scrollTo(), click());

注:,如果已经显示视图, scrollTo()不会有任务动作,
见ViewActions由Espresso所提供的视图操作。

检查视图是否满足断言

断言可应用于与当前选择的视图check()的方法。最常用的断言是matches()断言,它使用一个ViewMatcher断言当前选择的视图的状态。
例如,要检查视图是否包含文本“Hello!”:

onView(...).check(matches(withText("Hello!")));

注意:不要把“assertions” 作为OnView的参数,相反的,应该明确在校验块内检查。例如:
如果你想断言“Hello!”是视图的内容,以下被认为是不好的做法:

// Don't use assertions like withText inside onView.onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));

另一方面,如果要断言具有文本“Hello!”的视图是可见的 - 例如在视图可见性标志更改之后 - 代码是正常的。
注意:一定要注意相互之间的差别声称视图不显示和不存在。

开始使用onView进行简单测试

在本例中,SimpleActivity中含有一个Button与一个TextView。当按钮被点击的内容TextView变化”Hello Espresso!”。以下是如何用Espresso测试这个:

1.单击按钮

第一步是寻找有助于匹配按钮的属性。在该按钮SimpleActivity具有独特唯一属性的是

R.id.button_simple!
onView(withId(R.id.button_simple))

现在执行点击:

onView(withId(R.id.button_simple)).perform(click());
2.检查TextView现在包含“Hello Espresso!”
onView(withId(R.id.text_simple))

现在验证内容文本:

onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")));

使用ondata()来定位AdapterView(ListView,GridView…)

AdapterView 视图是一种适配器动态加载其数据的特殊类型的小窗口,一个最常见的例子就是ListView。内容是动态加载的,而onView()可以处理的是已经显示在屏幕上的组件。Espresso提供一个单独的处理,使用onData()作为切入点,它能够在AdapterView 子类工作之前,优先加载,进行匹配。

警告:

自定义实现AdapterView的View使用onData()方法进行匹配是有问题的,如果更改了getitem()方法。(ondata()会使用到getItem()方法进行匹配),在这种情况下,最好的做法是重构应用程序代码。如果你不能做到这一点,你可以实现一个匹配的定制 AdapterViewProtocol。

Log:
https://android.googlesource.com/platform/frameworks/testing/+/android-support-test/espresso/core/src/main/java/android/support/test/espresso/action/AdapterViewProtocol.java

开始使用onData进行简单测试

这个简单的测试演示了如何使用onData()。这个测试的目的是打开Spinner,选择一个特定的item,然后验证TextView包含在item中的子类。作为Spinner类是基于AdapterView它建议使用onData(),而不是onView()用于匹配的项目。

1.单击Spinner 打开选择列表
onView(withId(R.id.spinner_simple)).perform(click());
2.单击item“Americano”

对于使用listview来加载视图,有可能会有多于一屏的情况,有些元素是看不到的,通过使用onData()我们强迫我们想要的元素显示到当前视图层次。我们要匹配是一个字符串,它等于字符串“Americano”的item:

onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());
3.验证TextView包含字符串“美式”
onView(withId(R.id.spinnertext_simple))
  .check(matches(withText(containsString("Americano"))));

调试

当测试失败时,Espresso提供有用的调试信息:
记录

Espresso将所有视图操作记录到logcat。例如:

  ViewInteraction: Performing 'single click' action on view with text: Espresso

如果onView()未找到目标来看,一个NoMatchingViewException被抛出。您可以检查异常字符串中的视图层次结构,以分析匹配器为什么不匹配任何视图。*如果onView()找到匹配给定匹配的多个视图,一个AmbiguousViewMatcherException被抛出。将打印视图层次结构,并且匹配的所有视图都标记为MATCHES标签:

java.lang.RuntimeException:
com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException:
This matcher matches multiple views in the hierarchy: (withId: is <123456789>)
... ...
+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true,
is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true,
is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}****MATCHES****

AdapterView 警告

Espresso发出警告,用户进行匹配AdapterView子类。使用onView()操作会引发NoMatchingViewException和AmbiguousViewMatcherException:,最常见的解决方案是使用onData()。可以根据异常信息进行bug修复


引用:
官方文档:https://google.github.io/android-testing-support-library/docs/espresso/basics/index.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值