自动化测试框架Espresso(二) 基本用法

Posted by boredream on December 19, 2015

上一篇介绍了Espresso是什么及其环境搭建方法,这一章介绍基本用法

同样,官方的教程中是有详细说明的,如下

Google Github io 的介绍主页 https://google.github.io/android-testing-support-library/docs/espresso/index.html

安卓开发者中心的Training教程中的介绍 http://developer.android.com/intl/zh-cn/training/testing/ui-testing/espresso-testing.html

我这里也简单介绍下基本用法

首先对于UI为主的程序测什么? 那自然是测某个控件在点击/选中等动作触发时,会引起什么结果,是显示个Toast还是跳转页面等等

对应几个步骤

  1. 首先要定位到控件
  2. 让控件执行某个动作
  3. 判断执行动作后的结果

其实和正常的开发流程也很像,第一步findViewById定位控件,然后给控件添加动作监听,再在监听中写期望的执行结果 测试就是让动作实际的执行一次,然后判断实际结果是否为你期望的

一般公司这个让实际动作执行的过程都是人工的,也就是让测试点啊点 所谓自动化测试,就是让这些动作的执行用代码去自动触发


好了,根据这三个步骤我们分别介绍下Espresso框架中的方法

onView(Matcher viewMatcher) 定位控件 Matcher 匹配控件规则,常用的有:

  • 用id定位控件 ViewMathers.withId(R.id.xxx)
  • 用文本内容定位控件 ViewMathers.withText(R.string.xx 或 “xxx”);

其他操作诸如执行perform,验证check等都需要先定位控件然后再操作, 类似于普通功能代码中需要先findViewById定位,再能其他处理, 多了利用控件上的文字去定位withText等更多方法

注意: 如果需要定位的控件是在Toast/Dialog等地方,即不在主UI布局的结构(layout,及其include的layout)之中, 是不能直接定位的,可以在onView之后再添加如下代码即可

1
.inRoot(withDecorView(not(is(mActivity.getWindow().getDecorView()))))

但是要注意,这样处理后就无法定位主UI布局中的控件了

perform(final ViewAction… viewActions) 执行动作 ViewAction 具体动作,常用的有: 输入文本ViewActions.typeText(“123456”); 点击 ViewActions.click();

注意: 如果输入动作perform(typeText()) 之后直接执行其他操作可能会报错, 需要先关闭软键盘, 可以在后面添加 .perform(typeText(“blablabla”), closeSoftKeyboard())

check(final ViewAssertion viewAssert) 验证断言 测试是需要有个预想结果的,用计算器我输入1+1,按等于号执行之前我就敢断言结果应该是2, 那么如果是2就代表这个机器正确,如果不是2就代表错误,这个就是”Assertion断言” 人工测试的时候,自然都是”目测”看结果是不是对~这里代码中就需要用check验证我的断言assetion是否正确

ViewAssertion 断言结果,常用的有

  • 不显示 ViewAssertion.doesNotExist() 注意是不显示, 而不是字面意思的不存在,如果让一个View隐藏了GONE,则它就是doesNotExist的,虽然有这me一个控件,但它是不显示的(待进一步考证~)
  • 匹配 ViewAssertion.matches(final Matcher<? super View> viewMatcher) 比如验证控件是否显示就为 ViewAssetions.matches(ViewMatchers.isDisplayed()); 验证控件上是否显示某某文字就是 ViewAssetions.matches(ViewMathers.withText(“xxx”));

也可以使用反弹!再反弹!反弹无效…语句not, 比如not(isDisplayed())不显示, 类似于java里的 ! 符号

所以一个简单的应用,比如点击一个Button,然后某个TextView文字变为XXX, 就可以写个与之对应的测试代码

  1. onView 定位按钮, 然后 perform 执行点击 onView(withId(R.id.btn_confirm)).perform(click());
  2. onView 定位文字, 然后 check 验证内容是否 match 文字 XXX onView(withId(R.id.tv)).check(matches(withText(“XXX”)));

注意:

  1. 编写的时候可以不写静态方法的类名,然后根据提示静态导入对应包即可
  2. 测试是跨页面的,即如果第一步perform点击是触发了页面跳转,而第二步验证控件其实是在下一页也是可以的, 不用做任何处理设置, 但这样不限定页面也会有问题, api没有提供方法直接判断当前停留在的页面, 所以这里可以曲线救国,比如获取标题栏文字然后验证内容,用于判断当前页面是哪一个

AdapterView 操作, 比如ListView, GridView等,通常是希望操作某个position位置的item 方式比较多,也可以直接onView(withText())定位到控件,然后处理 但一般不能直接withId, 因为item通常都是使用一套布局的,因此不能定位到某位置的item 而onText也不太合适,ListView不会加载全部数据只会显示一页,如果文本不在当前页还是白瞎

因此,我们需要使用onData针对数据进行定位控件

onData(Matcher<? extends Object> dataMatcher) 用数据定位控件 参数还是Matcher和onView中一样,但是使用就不限于withId,withText了

比如定位一个列表中的某个数据对应item,就可以:

1
onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());

翻译语句的意思就是,获取全部(allOf)的,是(is)类型为(instanceOf)字符串的数据, 并从这些数据中定位到具体数据为(is) “Americano”字符串对应的View, 然后让他执行(perform)点击(click)

当然,如果内容是已知的,比如用ListView做一个设置列表,数据都是写死的,那自然可以直接withText定位了

(这部分onData还不够熟悉,会在后面系列的实例代码中用到时边研究边再补充介绍,大家也可以在官方教程中查看用法)


页面初始化

控件基本都是在Activity之中的,因此页面的加载是操作控件的前提 一般我们会在项目的测试包中新建一个同包命路径的测试类,类名一般为页面名+Test espresso1

而测试类和页面如何绑定呢,如下图申明一个Rule即可 espresso2 当运行该测试类时即会加载<>中对应的页面,即UserDeatilActivity

这种是最简单的直接打开,如果希望在页面打开时传入Extra数据 可以如下操作 espresso3

申明Rule时,传入第三个参数launchActivity为false, 如果不设置则默认为true即直接加载页面的 这里申明不默认加载,然后在测试方法中利用launchActivity(intent);方法加载页面同时用intent传入所需的extra 也可以在lauchActivity加载页面之前进行一些初始化处理,比如设置当前用户信息,设置token/session等

(这里的annotation也就是@部分都是JUnit里的,如果有研究过的同学应该比较熟悉,我是不太熟啦~ 而onView/perform等方法才是Espresso封装的简便方法)

注意: 如果测试代码先perform一个点击操作会发起网络请求,然后我们要check验证请求完成后是否提示一个toast, 正如第一篇中介绍的那样,Espresso是会有自己的处理

但有个问题,假如你用的是AsyncTask执行请求,那没问题,他内部已经处理好了, 如果用了其他框架,和可能就会出现同步的问题,他们内部没做处理,则Espresso无法判断是否它执行完成~ 这样就会直接运行下一步,在数据还未返回的时候可能就去check验证,自然就失败了

我平常应用的网络请求框架是Volley,好像不用特殊处理,直接OK的~ 其他的框架大家可以自行尝试,比如Retrofit, 这里有个网上搜来的设置方法 http://www.csdn.net/article/2015-08-19/2825493-using-espresso-for-easy-ui-testing

还有,如果想某一步停留,人工目测查看执行情况,也可以在测试代码适当位置添加Thread.sleep等待个一段时间

下一篇我们会介绍一个具体实例~ 解决测试代码编写最大最蛋疼的问题,究竟要在应用中测试哪些东西呢~