一 、引子

UI自动化,在移动互联网时代的今天,一直都是在各大测试社区最为火爆的一个TOPIC。甚至在测试同行面前一提起自动化,大家就会自然而然的问:“恩,你们是用的什么框架?appium?还是robotium?”

其实在笔者看来,UI自动化是一个ROI较低的测试项(ROI即return on investment,中文意思是投资回报率)。但UI自动化相比接口自动化、白盒测试等,它更贴近手工业务测试行为。对于刚起步测试左移、效率提升的团队来说,是最迅速的切入点,也是广大黑盒tester,提升自身技术能力的起跑线。

笔者接触UI自动化一年多,兼顾业务测试的同时断断续续地投入,曾经无数次的想放弃:

“才刚写完用例,怎么开发大哥又改了UI了?”

“维护这些破用例的时间,都够我手工测三遍了,真的有意义么?”

“测试框架自己有bug,我改用例也没用啊……”

“我调试的时候这个用例还是通的,放到daily里面跑就不通,到底怎么回事嘛!”

“adb怎么这么不稳定啊,老是断!!!”

“怎么跑着跑着就crash了,到底是被测应用有问题,还是测试代码有问题啊?”

“明明界面上有这个元素,怎么就是查不到呢?”

“这破手机,能不能别老是系统弹框……”

“这手机真是渣,adb screencap截个图,居然要三分钟才返回!”

“这些控件都没有id,没有text,层级还三天两头改,要我怎么查……”

“查了这么多论坛,怎么就没有人遇到过类似的问题呢?”

……

这些问题让笔者一度怀疑,UI自动化这个TOPIC,是不是根本没用,只是tester为了涨薪,或者为了摆脱重复无聊的手工业务测试,而YY出来自我欺骗的。

二、 问题分类及目标明确

笔者将以上所有的问题简单分成三类:设计类,环境类,细节类。一个好的设计模式,能够避免一部分问题;一套好的环境,可以让我们从乏味的维护工作中解脱;精益求精的细节,让测试用例更加可靠稳定。

图一 UI自动化常见问题

填掉这三类坑,基本上就获得了一套低成本高产出、少量维护、稳定可靠的UI自动化用例集。

三、 设计类问题分析与解决

“才刚写完用例,怎么开发大哥又改了UI了?”

“测试框架自己有bug,我改用例也没用啊……”

这类问题,我们需要从根上治。UI自动化开发,也应该是严谨的开发工作,它也需要设计模式,也是磨刀不误砍柴工。这里的设计,主要包括选工具、框架分层等。很多前辈都分析过UI自动化各类工具的优缺点,对工具选用笔者不再赘述。主要依托uiautomator来介绍下笔者认为比较巧妙的用例框架设计。

1 优化测试代码框架

无论你选择appium、uiautomator、robotium还是espresso,刚入门时,看到的sample应该大致都是这样的。

图二uiautomator和espresso逻辑样例

问题在哪里?这些sample过于简单,都只教了我们UI自动化三元素:怎么查找元素、怎么操作元素、怎么校验结果。如果我们按照大多数分享帖或GitHub sample来写作自己的case。最后这种没有任何设计模式的框架,肯定会面临重构。拿上面的espresso来说:

假如action_save这个id开发改了,而你的用例集中,有30个步骤用例到了这个id,一个个去改,是不是要疯?

不厌其烦的重复写onView(withXX(xxx)).perform(click())这一长串,你不烦?

笔者是如何做的?分层设计和PageObjects模式。这两个方法,基本解决了笔者遇到的图一中所有的设计类问题。

图三 框架设计建议

按照图三进行分层设计后,得到如图四的测试代码包。

图四 分层后的用例框架

PageObjects模式发源于selenium社区,它的目的是减少重复代码,当开发修改UI时,测试只需在有限的位置修改代码。如果大家想深入了解PageObjects,请参照如下wiki:

https://github.com/SeleniumHQ/selenium/wiki/PageObjects

http://blog.csdn.net/kittyboy0001/article/details/25219053

我们来看一下,现在手管首页Page包中的代码和页面。

图五 手管首页Page层部分代码

回忆一下上面的google提供的sample,再对比引入分层设计和PO模式前后的代码,点击图五中的一键加速:

图六 引入PO前后代码对比

带来的好处,当然不仅仅是业务用例代码更清爽。

通过将查找和操作封装到基础层中,这部分代码就具体业务无关了,即使拿到其他产品中也可以复用;

通过page层的分离,所有的与业务相关的id,text等都被限定在了page包中,哪怕开发改了UI,修改page包特定的页面中对应的元素就好了。

对page包进行合理的业务拆分,比如将手管分成 MainPage(主页),SoftwareManagerPage(软件管理页),WiFiManagerPage(WiFi管理页)等,在开发改了某个具体业务的界面后,测试能够迅速知道测试代码需要改哪里。

2 兼容资源混淆的测试代码

除了整个框架的设计,有时候一些小问题也可以经过巧妙设计。比如资源混淆的问题。

图七 资源混淆

如图七,在手机管家的发布包中,用uiautomatorviewer dump下来发现,一键优化的button,其resource-id是o3,但其实开发coding时,定义的id显然不会用这种没有任何字面意义的代号,它在混淆之前叫optimize_button。

纯黑盒的UI自动化,也许你会摒弃optimize_button,直接写o3,但这样显然不够科学,既带来了严重的代码可读性问题,同时一旦版本迭代,混淆变了,o3也许就变成了o4。或者你会让开发给你测试的包,不要混淆,但如果想用UI自动化测试已发布的apk呢?

=解决该问题,也得从PageObjects说起。回到图五中OPTIMIZE_BTN的定义,这个静态变量并未在page中初始化,只有一个@FindBy的注解。其实,在框架层驱动测试开始前,框架会先调用如下图八所示的setAllField来初始化所有的page页面。

如果被测应用未混淆资源,该方法只是将@FindBy中的值赋值给Field。

如果被测应用已混淆资源,该方法则会从mObfuscationMap(未贴出全部代码,实际是解析一个开发提供的混淆表,以原始id为key,混淆id为value的HashMap)中读出对应的id对应关系,将混淆后的id赋值给Field。

图八 Page层动态初始化

四、环境类问题分析与解决

“adb怎么这么不稳定啊,老是断!!!”

“明明界面上有这个元素,怎么就是查不到呢?”

“这破手机,能不能别老是系统弹框……”

“这手机真是渣,adb screencap截个图,居然要三分钟才返回!”……

引子中提到的这些问题,根据经验,多半你的环境执行环境还不够稳定。

1 ADB相关问题

已知的ADB不稳定原因如:电压不稳,各类手机助手的干扰,系统版本与ADB版本不匹配、ADBcrash等等。如果我们迎难而上,去重写ADB,投入将无限扩大。所以建议主要的解决方案,还是尽量规避。

a) 选用可靠硬件规避电压不稳定,github上的STF项目组有过成熟的经验,选用性能更优的USB分接器,电压和可靠性会有更稳定的表现。(附上链接,wiki Recommended hardware一节中有不同硬件详细的性能对比,https://github.com/openstf/stf)

b) 屏蔽各类手机助手的干扰。91助手、豌豆荚等,基本都在adb上做了二次开发,它们会与原生adb间有兼容性问题。建议直接使用Linux/MAC系统作为运行环境以屏蔽这类干扰。

c) 降低用例在执行过程中对环境的依赖。Appium这类自动化工具,每一个测试步骤都需要PC端的appium server和测试手机端的bootstrap交互消息。测试过程中只要USB连接不稳定,都会导致整个测试套的失败。所以笔者认为,使用更原生的uiautomator会是更好的选择;同时,测试过程中的日志、截图等,也尽量在测试手机上做持久化。

2 弹框问题的解决

权限弹框,是手管UI自动化中的一个大坑。如下图,是测试手管过程中,在华为手机上遇到的部分权限弹框。这些弹框,并不会用例每次执行都弹出,不同厂商的弹出框也不一致。显然点击弹框的逻辑,写在case逻辑中,只会导致自动化变得更复杂更不稳定。

图九 各类权限弹框

uiautomator的watcher,能够完全实现点击弹框和用例逻辑的解耦。当前笔者的实现逻辑是,监听弹框上的某个控件,当该控件出现时,执行action来点击掉其中的取消或确定按钮。这样,用例就只需关注业务逻辑,而任何时候的弹框,都由watcher来自动点击。如下图中,checkForCondition关注条件,action是操作。

图十查找型Watcher

将所有的watcher分不同的手机厂商进行注册后,再调用runWatchers(),然后再执行用例。该方法可以在@BeforeClass中或者RunListener的testRunStarted中调用。当然,如果某个用例不想某个具体的弹框被watcher点击掉,也可以调用removeWatcher()反注册。

图十一 注册监听器

Watcher并不能解决所有的弹框问题。例如,在开启WiFi的场景中,由于WifiManager的setWifiEnabled和UI上的弹框点击是同步的(意思是调用了setWifiEnabled之后,如果界面上不点允许,该方法是不会返回的),使用上面的watcher方式并不会点击WiFi权限申请的允许。这时,就需要用到线程方式来解决(如下图十二),调用setWifiEnabled前,先启动一个线程等待弹框弹出。

图十二 多线程方式点掉弹框

五、细节类问题分析与解决

“我调试的时候这个用例还是通的,放到daily里面跑就不通,到底怎么回事嘛!”

出现上述问题,多半是因为我们的用例细节不够严谨。这类问题,往往决定着我们自动化用例集,是不是能从90%的case通过率,提升到100%。

1 顺序逻辑的用例

自动化相比手工,它只会关注code告诉它的验证点,所以选择逻辑在用例中应该是禁用的。如下图十三中右侧的case,如果用例执行到if中,也许else流程中存在BUG,反之亦然。此时考虑拆分用例,左侧才是理想的用例逻辑。

图十三用例逻辑

另外,写作case时,一定要牢记,只有我们告知程序要assert,它才会去assert。查找,操作,断言,UI自动化三要素缺一不可。

2 解耦的用例

在testng中,会提供dependsOnMethods注解,似乎在鼓励写作用例时,使用用例间依赖。但笔者认为,用例间的依赖,会带来不必要的维护成本。只有高度解耦的用例逻辑,才能够更加健壮的支撑用例执行顺序调整、用例增删、出现异常场景后,A用例失败不会导致B用例也失败。

3 优化等待

有时候会遇到以下场景,虽然原生的自动化工具提供了等待元素可见的方法,但使用起来,还是无法真正等到元素可见。针对这个问题,如下图的waitCondition方法是一个不错的方案,它相对于thread.sleep来说,更节省时间。

图十四反复等待方法

4 不用绝对坐标点击

绝对坐标点击,在不同尺寸屏幕上无法兼容。

第一方案应该是,推动开发对需要用到的控件添加ID或Accessibility。但根据经验还是会有一些场景需要用到坐标点击:

1, 考虑投入产出比,为所有控件添加id的成本过高;

2, 动态布局添加的ID都一样;

3, 存在非xml布局的界面(代码中直接布局)。

这时,笔者依然不建议mDevice.click(100,200)这样的坐标点击。有以下两种值得一试的方案。

a) 找到相邻控件坐标,计算当前控件的绝对坐标。如下图十四,uiautomatorviewer中点击右上角警告小三角,会得到有一些元素(黄色控件),是可能无法找到的。而使用相对坐标就是说,我们可以获取它相邻控件的坐标,然后减去或加上一个比较小的px值,再点击计算后的坐标即可。

图十五 相对坐标

b) 使用屏幕尺寸计算相对位置。在测试开始,将屏幕尺寸存下来,使用百分比的方式计算得到需要点击的位置。如下,点击【50%宽度,80%高度】的位置。

六、总结

UI自动化测试是一门学起来很简单,用起来很麻烦的测试技术。

想要入门,两周就可以了解清楚uiautomator或espresso这类工具。UI自动化,无非就是查找元素、操作元素或设备、验证结果。这三个步骤循环多次,就是一个用例。

但要用好,并产出能效,需要走的路其实很长。由于篇幅限制和知识有限,这里不可能把所有的问题一一列出。对于所有这些问题,无非两个思路:一是绕过,二是解决。

选一个尽量简化,尽量底层的工具(uiautomator或espresso),从根上绕过一些工具会存在的问题;

采用良好的设计模式,让自己的框架更稳定,生命周期更长,维护成本更低;

明知道会耗费很多时间精力,收效却很小的环境问题,尽量绕过;

优化用例逻辑和细节,使之稳定可靠,更能说服别人相信自动化的测试结论。

最后,祝愿大家在UI自动化的道路上越走越顺!

文章来源:http://www.uml.org.cn/Test/201710253.asp

小心!做 UI 自动化一定要跨过这些坑的更多相关文章

  1. 使用appium+python做UI自动化的demo

    使用appium+python做UI自动化的demo 案例使用的知乎app,下载最新的知乎apk,存在了电脑上,只需要配置本机上app目录,不需要再配置appPackage和appActivity # ...

  2. 如何做ui自动化---步骤详解

    第一步: 得到功能测试的常规用例,查看是否可以进行自动化,要明确,自动化不是为了自动化而自动化,自动化是节省人力,主要做回归测试,如果变动性特别大,不建议做自动化,具体可查看其它文章“什么适合做自动化 ...

  3. ui自动化测试数据复原遇到的坑——1、hibernate输出完整sql

    公司老项目使用SSH+informix+weblogic+IE开发,我们要做ui自动化测试,其中的测试数据复原,我打算通过hibernate输出sql,然后把插入.更新的sql改为delete或upd ...

  4. selenium做UI自动化时,模拟鼠标各种操作的ActionChains的用法

    1.selenium做自动化的时候,需要模拟鼠标进行单击.双击.右键.拖拽等操作,selenium提供了ActionChains类来进行处理. 2.执行原理:当你调用ActionChains的方法时, ...

  5. ui自动化测试数据复原遇到的坑——2、python连接informix时pytest报致命错误Windows fatal exception: access violation

    python连接informix只能通过jdbc(需要先部署java环境.我试过到IBM上下载ODBC但结局是失败的),在执行pytest时发现有一串报错(大致是下面的这样): Windows fat ...

  6. UI自动化,你值得拥有

    去年春节联欢晚会,为了那张“敬业福”,全家都卯足了劲儿“咻一咻”,连节目都顾不上看了.当时我就想,要是能自动化该多好,不停点击屏幕,屏幕不疼手还疼呢,何况还不好分心,生怕错过了“敬业福”.玩“咻一咻” ...

  7. UI自动化测试之Jenkins配置

    前一段时间帮助团队搭建了UI自动化环境,这里将Jenkins环境的一些配置分享给大家. 背景: 团队下半年的目标之一是实现自动化测试,这里要吐槽一下,之前开发的测试平台了,最初的目的是用来做接口自动化 ...

  8. java -ui自动化初体验

    本文来讲一下ui自动化的环境搭建,以及最初级的打开网页操作 说起ui自动化,想想大概是前年的时候我开始接触和学习的吧,怎么说呢无论是pc还是app,ios还是android,确实很神奇而且很华丽,但是 ...

  9. UI自动化(七)selenium简述

    1.什么是ui自动化模拟人用代码的方式去操作页面2.为什么要做ui自动化后期迭代的时候,老功能比较多,人工维护成本大这时候考虑引入ui自动化3.什么时候做ui自动化项目稳定,不在修改的某些老功能,为这 ...

随机推荐

  1. Golang 模块(Module)官方手册

    官方原文: https://github.com/golang/go/wiki/Modules Go 1.11包括此处建议的对版本模块的初步支持.模块是Go 1.11中的实验性加入功能,并计划纳入反馈 ...

  2. webview学习

    Android中WebView使用6,js调java实现播放视频 https://blog.csdn.net/zhaihaohao1/article/details/77993890 android ...

  3. nginx日志设置

    环境:nginx1.16.1 (1)日志类型:access_log(访问日志) error_log(错误日志)rewrite_log 访问日志:通过访问日志我们可以得到用户的IP地址.浏览器的信息,请 ...

  4. Nginx 高级配置-第三方模块编译

    Nginx 高级配置-第三方模块编译 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数--add ...

  5. php模板模式(template design)

    没有写停止条件,所以会一直运行哟. <?php /* The template design pattern defines the program skeleton of an algorit ...

  6. Java 获取对象全部属性 包括 父类属性

    今天由于业务需要,看一段数据库中的表转化成用户可以看懂的数据,也就是把一些字段比如Date用ms存的,转化为'yyyy-MM-dd'这种格式,但是由于字段太多,所以利用Java反射机制自带的BeanU ...

  7. Linux传输指令-scp

    本地传到远程 scp -rf bt.plist cjp@centos:~/下载 从远程下载到本地 scp -rf cjp@centos:~/下载 ~ 参数详解 参数 描述 -a 尽可能将档案状态.权限 ...

  8. 监控进程cpu meminfo

    https://github.com/cdrandin/cpsc_351 https://github.com/cdrandin?after=Y3Vyc29yOnYyOpK5MjAxNC0wNy0xM ...

  9. 201871010126 王亚涛 《面向对象程序设计(java)》 第四周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  10. css display:inline