本文记录了在AWS Device Farm上进行Appium TestNG进行手机应用UI自动化测试的流程及遇到的问题,及具体的解决方法。同时记录了使得测试脚本更稳定的一些代码写法。
Device Farm是Amazon Web Service推出的云应用测试工具,允许你在数量众多的物理移动设备上测试你的应用。DF提供了两项功能。其中Remote Access允许你通过网页远程操控云端的设备,并可上传安装自己的应用。另外Automated Tests还允许你上传自己的自动化测试脚本,在云端的设备上执行自动化测试。
DF支持多种UI测试框架如:Appium Java JUnit, Appium Java TestNG, Appium Python, Calabash等。经过与JUnit的对比,最终我选择了Appium Java TestNG。
类似的平台有Xamarin Test Cloud以及国内腾讯的WeTest上的云真机。
Device Farm使用步骤:
1、本地设备上测试通过你的测试脚本
2、将脚本按照官方教程使用Maven方法打包成zip文档
3、上传zip以及ipa/apk,选定设备池,执行测试
4、等待执行完成,分析执行结果,修正直到全部通过
备注:
唯一的麻烦是使用官方特定的Maven打包方式,可以直接github下官网的Demo,复制到自己的项目。
踩过的坑:
autoAcceptAlerts和autoDismissAlerts在XCUITest中被弃用了,对话框需要代码中处理。
android:
Valid locator strategies for this request: xpath, id, class name, accessibility id, -android uiautomator
ios:
Valid locator strategies for this request: xpath, id, name, class name, -ios predicate string, -ios class chain, accessibility id
IOS必须指定bundleId、UDID、deviceName
Android虽说deviceName没有意义,但不指定编译不通过
IOSDriver中没有AndroidDriver的许多方法,例如:pressKeyCode();
对于不能获取焦点的EditText,IOS中也能使用sendKey()来输入文本,而Android只能使用driver.pressKeyCode(),向设备发送键值的方式。
对于一个列表而言:
IOS会把看不见的未显示到当前屏幕的元素也找出来,这个时候需要使用isDisplay来判断是否可见。
因为不可见意味着不可点击。而Android初步测试不会把看不见的列表元素找出来。
driver.swipe(start_x, start_y, end_x, end_y, duration);
这里的end_x, end_y实践证明就是目的坐标,论坛上许多人说是偏移量,版本不对吗?
有的时候findElement找不到的时候,使用findElements获得数组,并使用对应的下标,常常可以找到。
特别是对付对话框里的元素
appium没有提供直接判断是否找到元素的方法,可以用findElement方法是否抛出NoSuchElementException来判断,或者判断findElements返回数组的size是否为零。
对于滚动查找列表项的操作,会发生目标项只有部分显示就被找到的情况。这个时候如果你需要偏移坐标查找如CheckBox之类的元素,有可能发生偏移后的坐标超出屏幕的情况。
此时相应方向的坐标需要防止越界。可以在找到后再滑动一次屏幕,以保证目标完全显示。click操作也是如此,因为click默认是tap元素的中心坐标,而元素的中心坐标可能尚未显示。
Appium支持中文:
在Capabilities 中添加
capabilities.setCapabilities("unicodeKeyboard",true);
capabilities.setCapabilities("resetKeyboard",true);//必须
在设置上面两个属性后,如果脚本中途崩溃,容易出现系统输入法被替换为Appium输入法的问题,该输入法是没有界面的。
错误:xcodebuild failed with code 65
解决:将WebDriverAgentRunner安装到iphone上。方法如下
1、使用Appium Inspector建立Session成功,会自动安装
2、运行测试代码建立Session成功,会自动安装
3、使用Xcode或xcodebuilder将WebDriverAgent直接安装到设备上
4、以上都不行,则到WebDriverAgent的github官网下载最新的替代现有的
UI自动化测试具有不稳定性,任何微小的延迟或界面不同于预期,脚本就会失败。要写出在多种机型上正确运行的脚本,需要不少时间,如果你要结合云测试平台进行云端设备的自动化测试,不稳定性会更高。所以设定合理的等待时间,在可能出现弹框的地方进行判断。
AWS Device Farm注意:
AWS官网的文档很可能不是最新的,比如:官网最新支持appium1.6.3, Github上最新支持appium1.6.5。官网说明项目需要修改POM.xml文件,Github上直接给出详细步骤,对于详细技术文档,Github才是王道,官网更新常常不及时。
Device Farm会把所有的JUnit Test Case转换成TestNG Test Case。但官方说不会有影响。
实际上对于注解的支持就不一样了,例如JUnit中的@BeforeClasss在被转换成TestNG后是否会相当于TestNG的@BeforeClass,并且JUnit要求@BeforeClass方法必须是Public static修饰,而TestNG并无这样的限制。所以还是改用TestNG吧,免得疑神疑鬼,况且需要改的也只是注解和稍微调整逻辑而已。
Device Farm(Appium1.6.5)已经可以重写DesiredCapabilities覆盖服务器。例如添加:NoReset = true。官方例子中明确写出DesiredCapabilities必须为空,信息不同步,那指的是1.4.3版本的appium。
(不能重写的信息来自Github官方例子,可以重写的信息来自stackoverflow的官方工程师答疑)
Device Farm上IOS使用driver.manage().window().getSize().getWidth();在执行getSize()的经常时候返回null,Android没有这个问题,有时候需要用固定数值。
同样在执行element.getLocation()时也是经常直接崩溃。后来又莫名奇妙好了,这么不稳定,测试个球。
AWS默认每个用例执行后都会resetApp。也就是清空所有状态。
所以如果你的app需要登录,则每个用例执行前都需要重新登录一遍,
方法一:可以把Login的逻辑放在JUnit的@Before或TestNG的@BeforeMethod方法里。
方法二:设置Desired Capabilities的NoReset设为true,让其不要在会话前重置应用状态
理论上本地使用Appium相同版本测试通过的代码,放到DeviceFarm上是不应该有问题的,现实却不是这样。Device Farm上提供了多种记录:Vedio、Appium Java Output、Appium Server Output、Logcat等。答案只能在这里找了。
远程调试远比本地调试麻烦的多,网络的限制,实时性的限制等。远程调试一次花费的时间远比本地调试来的长。并且只能通过返回的日志信息查找问题。
千奇百怪的手机,就有千奇百怪的弹框,还有两个平台的适配,耐心方得始终。
Device Farm需要借助Maven将项目打包成指定格式的zip格式,如果官网看不明白,直接上github下载官方Demo,参照它的代码结构写即可。主要是一个pom.xml和zip.xml。官方Demo使用Page Object的结构组织代码,可以了解一下:https://github.com/SeleniumHQ/selenium/wiki/PageObjects
Device Farm允许一次测试选择多部设备,并且是并行执行测试,如果你的脚本包含了测试登录功能,那么很可能出现一个账号在多台设备间相互踢出再登录的情况。这时候只能一次选一台设备单独执行,除非能在登录时判断不同设备登录不同账号。
恼人的系统对话框
做机型适配时,最麻烦的就是系统对话框了,不同系统版本,不同厂商的权限对话框出现时机可能不同,可能多个权限对应一个对话框,也可能多个权限对应多个对话框。还有偶尔出现的其他app的对话框,这个没辙。例如google service被登出,iTune账号在其他平台登录被提出,IOS推送服务Push Notification失败,千奇百怪,写代码有什么难的,适配才难。
保证对话框位置固定后再查找元素:
对话框查找元素时使用的id,最好是包含包名的如com.hello.name:id/button1。使用button1容易找不着。
弹出对话框时,需要注意findElement操作执行之前对话框是否显示到位(动画效果完成),动画执行过程中findElement获取Element的坐标不是最终的坐标。所以会出现,findElement可以找到,click等交互操作没反应的情况。同样需要注意在对话框显示之前等待一定时长保证软键盘完全消失。
如果发现查找对话框元素时,同时查找到了对话框下onStop状态的元素,则可能是使用findElements找数组元素时,在该元素还是onResume状态时就找到了,而当你对其进行操作时,该元素已经onStop不可交互了。这时候可以等待一下对话框完整展示再查找。
调试系统权限对话框
系统对话框如权限对话框只有在第一次启动App时才会显示,允许过后就不再显示了。这造成适配对话框的代码不好测试。每次测试都需要进系统权限界面把授予的权限取消或者IOS需要重新安装ipa。可以在@AfterTest中执行driver.resetApp()将App的状态重置。这样每次测试的app都和重新安装一样。
转载于:https://blog.51cto.com/weijiancheng/1968828