本篇侧重于简单的描述MAT的概念,期间掺杂些许个人的理解,不正之处欢迎指正
一、关于UI自动化测试的闲谈
在本篇开篇之处,我觉得还是很有必要强调下UI自动化测试的概念,只有理解概念之后才能对要做什么、能做什么有一个清晰的认知,也可以更自然地了解本文所阐述的内容。
1.1 什么是UI自动化测试
通常意义上,软件开发过程中的测试方式可以分为以下三个层面:
其中单元测试和集成/接口测试的概念我们就不过多描述,而且作为较底层的测试方式往往需要业务研发人员的参与
而UI测试则是目前MOA大部分测试人员的主要工作内容,针对UI层的功能进行测试,例如,我们不断重复的对一个表单提交、结果查询等功能进行测试
UI自动化测试就是通过相应的自动化测试工具来模拟这些操作,从而解放重复的劳动工作,UI自动化测试类似于让机器去模仿人的行为,让它自己去统治整个测试工作。
1.2 原则:所得即所见
既然UI自动化测试是让机器去模仿人的行为,那实际上也应该认为机器只能理解人所能理解的东西。比方说,当我去人为地做一些测试的时候,我所期待的只是UI上的变化可以符合我的预期,至于它背后的数据是怎样的实际上我并不care也不能care
因此,在做自动化测试时要有个最基本的思路:把自己当成用户,只关注我能看到的东西。
我们把自己作为使用程序的最终用户,要让机器模拟我的测试过程,那么就需要针对那些我能看到的东西,也就是UI组件进行验证。比如说,作为用户并不关心某个网络请求返回值的具体数据是否正确,我关心的是能在UI上看到希望看到的结果
我们在此处所描述的UI自动化测试更倾向于黑盒测试,当然,MAT可能会涉及部分的源代码识别,但是毕竟是一种高级运用情景,因此MAT对编程人员的要求如下:
-
黑盒测试。 也就是不需要了解详细代码,从而先满足了了测试和开发的分离,在可以不了解源码实现的层次上,进行功能测试;
-
了解测试基础代码。一方面要能编写测试代码,其次也要了解一定的开发情况(譬如列表的adapter,稍后会说到);
1.3 原则:适度的UI自动化测试
为什么1.1图中要画成一个金字塔形,则不是长方形 或倒三角形呢? 这是为了表示不同阶段所投入自动化测试的比例 。
因此不要妄图实现全面的UI层的自动化测试,那是一个绝对的劳民伤财举动,投入了大量人力时间,最终获得的收益可能会远远低于所支付的成本。
因为越往上层,其维护成本越高,尤其是UI层的元素会时常的发生改变
二、“Espresso为主,Robotium为辅”
到这里,我们基本已经明确了,UI自动化测试是辅助我们减少重复的UI操作验证,那么我们如何去构建这样一个自动化的过程呢?无疑要借助一些测试工具。
当前市面上已经有不同的测试工具,他们各自有不同的优缺点,在本篇我们不做详细的讨论,更侧重于实际运用,有兴趣的童鞋可以自行百科
最终,我们为moa-android选定了以“Espresso为主,Robotium为辅”的UI自动化测试环境(本篇不对Robotium进行过多描述,仅需要了解Robotium是对Espresso一些缺陷的补充)
三、Espresso简介
Espresso是Google官方提供的Android UI自动化测试的框架.
之所以命名为Espresso(浓咖啡),就是想让Android码农们轻松的写完自动化用例后能享受着咖啡,看着自动化测试"飞".
为什么选择Espresso测试框架?
很简单,Espresso是Google针对Android平台开源的一款最新的Android自动化测试框架。不用考虑跨平台、兼容性等各种问题,最贴合需求才是最好的
-
使用 Espresso,便于书写简洁、优雅、可信赖的 Android UI 测试
-
核心 API 小巧、可预测、易于学习并且依然保持对定制的开放
-
Espresso 测试清晰的描述异常、交互和断言,而没有样板内容、自定义基础设施或凌乱的实现细节的干扰
-
Espresso 测试运行非常快!它会在应用 UI 处于静止时对其进行操作和断言,而使你远离了等待、同步、睡眠
做各个测试用例的一个通用的思路就是:找到某个元素,做一些操作,检查结果。这里包含了三个流程:
-
【找元素】:找到UI上测试所针对的元素;
-
【做操作】:给这个元素做一些操作;
-
【检查结果】:这个元素做出了我期望的行为。
再直观一点,我们测试向一个EditText输入一段文字,那么整个过程就可以描述为:
-
【找元素】:找到EditText组件;
-
【做操作】:向EditText输入字符串;
-
【检查结果】:EditText显示了我输入的字符串,验证内容是否符合。
以上三个小步骤实际上也是我们作为用户在使用一个APP的时候所遵循的流程。而我们的测试也是基本遵循这样一个流程的。
四、 Espresso简单事例
在下面我们给出一个简单的示例,让大家对Espresso有一个直观的了解,当然在实际的运用中由于涉及同步|异步、列表交互等会使得代码比以下示例复杂许多,但是道理都是共通的。
1 | @Test |
2 | public void greeterSaysHello() { |
3 | onView(withId(R.id.name_field)) |
4 | .perform(typeText( "Steve" )); |
5 | onView(withId(R.id.greet_button)) |
6 | .perform(click()); |
7 | onView(withText( "Hello Steve!" )) |
8 | .check(matches(isDisplayed())); |
9 | } |
代码逻辑也是典型的三步:
-
首先通过withId方法找到了id为name_field的EditText组件,并且调用typeText方法对其进行设置text内容为"Steve";
-
再通过withId方法找到id为greet_button的Button组件,掉头click方法模拟点击该按钮;
-
最后通过withText方法查找text内容等于"Hello Steve!"的TextView组件,调用check方法判断该组件是否匹配(matches方法)是否可见状态(isDisplayed)
五、Espresso 详细说明
Espresso在安装和使用过程中涉及的到的信息量较多,我已经进行了相关的学习文档撰写,并提交到公共目录下
- 初级:Espresso的基本使用
- 进阶:从源码角度进行解读,并自定义相关过程
六、MAT结构
由于UI自动化测试中必然涉及相关公共模块,因此对代码结构进行合理的规范也是必须的
初步完成了几个模块的自动化测试案例,并给出了基本的代码结构风格以及撰写方式
七、运行
- 单个案例运行,在测试案例上右键--run
- gradle assembleAndroidTest 将执行全部的测试案例并形成报表
后记
总觉得,最后还是有必要加上这些话。
目前,我们对UI自动化测试的定位应当明确,它应该是作为人工测试的一种补偿,而不是替代方案
UI自动化测试归根揭底只是帮助我们完成一些简易的机器可清晰识别的测试案例,而一些复杂的涉及多端多账号必然无法完美的支持
因此,对于现阶段来说,如何适当的投入人力进行UI自动化测试的编写,这个度需要很好的把控
而且要清晰的认识到,自动化的测试过程是不能完全取代人力的,至少现阶段是这样的