分享

Appium自动化测试

 昵称38290836 2019-03-04

一、Appium简介

Appium是一个移动端的自动化框架,是跨平台的。可用于IOS和Android以及firefox的操作系统。
· 原生应用是指用android或ios的sdk编写的应用;
· 移动网页web应用是指网页应用,类似于ios中safari应用或者Chrome应用或者类浏览器的应用;
· 混合应用是指一种包裹webview的应用。

1.1 Appium架构原理

Appium是在手机操作系统自带的测试框架基础上实现的,Android4.2版本以上使用的是UIAutomator,Android4.2及以下使用的是基于Android Instrumentation框架实现的自动化测试工具;iOS是基于iOS自带的UI自动化工具UIAutomation实现的。

Appium由客户端和服务器组成,客户端与服务器通过JSON Wire Protocol进行通信。下图简单的介绍了各部分。

Appium-架构

Appium Server:
Appium server使用node.js写的http服务器,遵守REST风格。主要作用是接受从Appium客户端发起的连接,监听客户端发送来的命令,将命令发送给Bootstrap.jar(或Bootstrap.js)执行,并将执行结果通过HTTP应答反馈给Appium客户端。

Bootstrap.jar:
在Android手机上运行的一个应用程序,它在手机上扮演TCP服务器的角色。当Appium需要运行命令时,Appium服务器会与Bootstrap.jar建立TCP通信,Bootstrap.jar负责运行测试。

Appium Clients:
是一个扩展WebDriver 协议的库,负责与Appium服务端建立连接,并将脚本的指令发动到服务端。支持多种语言。

Session:
Appium的客户端于服务端之间进行通信都必须在一个Session的上下文中进行。客户端在发起通信的时候,会首先发动一个叫“Desired Capabilities”的JSON对象给服务器。服务器收到该数据后,会创建一个Session并将Session ID返回给客户端。客户端可以用此ID发送命令。

Desired Capabilities:
是一组设置的键值对的集合,主要用于通知Appium服务器建立需要的Session,其中一些设置可以在Appium运行过程中改变Appium服务器的运行行为。

1.2 Appium优缺点

优点:

  • 支持多种应用程序的测试
  • 支持使用多种语言来编写测试脚本
  • 被测试的应用程序不需要特殊的编译
  • Appium支持应用之间跳转的测试

缺点:

  • 由于服务端运行在电脑上,该工具必须连接电脑才可以运行
  • 只能用于UI的自动化测试,在很多情况下的测试验证只能通过验证界面来进行

1.3 WebDriver

Appium采用底层驱动商提供统一的WebDriver API,它和Selenium有着千丝万缕的联系,很多方法的使用都很相似,可以参考笔者之前写过的Selenium文章。

Selenium自动化测试-入门
Selenium自动化测试-unittest单元测试框架使用

二、Appium环境搭建

2.1 安装Appium运行环境

  1. Android运行环境
    安装Android SDK后,并将其加入到系统环境变量中。
  2. 安装Python
  3. 安装Node.js
    是为了用命令行的方式启动Appium。
  4. 安装Appium服务器
    可以从此网站下载安装http:///

2.2 Appium服务器启动

打开Appium软件后,点击右上角的三角形,可以打开启动服务器,如下所示:

appium运行

如果输出类似如下信息,没有错误提示,就表示启动成功了。

> Launching Appium server with command: C:\tools\Appium\node.exe lib\server\main.js --address 127.0.0.1 --port 4723 --platform-name Android --platform-version 23 --automation-name Appium --device-name '8c28b78c' --log-no-color> info: Welcome to Appium v1.4.16 (REV ae6877eff263066b26328d457bd285c0cc62430d)> info: Appium REST http interface listener started on 127.0.0.1:4723> info: [debug] Non-default server args: {'address':'127.0.0.1','logNoColors':true,'deviceName':'8c28b78c','platformName':'Android','platformVersion':'23','automationName':'Appium'}> info: Console LogLevel: debug
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

启动之后,可以在浏览器里面访问http://localhost:4723/看看是否有反应,如果正常启动的话,肯定是有反应的。我们需要在设置中改变一些设置,也可以将界面中的log信息导出到文件中,便于我们处理。

appium setting

appium setting2

三、编写脚本前的准备

3.1 查看页面元素

Native APP:
我们可以使用Android SDK安装目录下的uiautomatorviewer来查看APP的页面元素,~\sdk\tools\uiautomatorviewer.bat

appium uiautomator

也可以使用Appium inspector来查看,但是没有uiautomatorviewer那么好用。

appium inspector

含有webview的APP:
可以通过Chrome的DevTools来获取,在Chrome中输入chrome://inspect/#devices后,如果有连接上的设备,可以点击inspect进入查看页面。

devtools

不过,有时通过这种方法是无法获取到页面的,原因可能是被测程序的WebView没有开debug模式等。这时我们可以获取当前页面的URL然后通过Chrome或Firefox等来访问并且查看元素。

3.2 相关文档

这个网站上说明了Appium的方方面面,如设计理念、各个平台的安装、脚本编写等等。http:///slate/cn/master/?python#about-appium

通过appium在GitHub上的介绍我们可以获取编写脚本的一些方法,这里给出的是Python语言的链接。https://github.com/appium/python-client

3.3 简单示例

用Python写Appium的脚本时,只需以下几步即可以构造一个基本的用例,如下代码片断所示:

        #构造Desired Capabilities        desired_caps = {}        desired_caps['platformName'] = 'Android'        desired_caps['platformVersion'] = '6.0.1'        desired_caps['deviceName'] = '8c28b78c'        desired_caps['appPackage'] = 'com.ss.android.article.news'        desired_caps['appActivity'] = '.activity.SplashActivity'        driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)        #1.获取元素        videoBtn = driver.find_element_by_name('视频')        #2.操作元素        videoBtn.click()        #3.结果验证
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

我们首先需要构造一个Desired Capabilities,设置一些参数,用它来连接到APP中,然后就是进行UI自动化操作的标准3步了。

  1. 获取页面控件
  2. 操作控件
  3. 控件信息验证

对这三步很熟悉了之后,我们再在这个基础上做一些封装,使得脚本更加健壮,可维护性更高。接下来按照以上几步来一步步做吧。

四、Desired Capabilities说明

Desired Capabilities就是一组设置,这些设置可以让测试脚本控制Appium的运行行为。下面对这些设置做一个简单的说明。从其官方网站我们可以得到全面的信息,网址为:http:///slate/en/master/?java#appium-server-capabilities

4.1 与Appium服务器相关的

Capability 是否为必填项 描述
automationName Appium使用的测试引擎 Appium(默认)
platformName 被测设备的系统平台 iOS,Android,Firefox OS,null(默认)
platformVersion 手机系统版本 如6.6.1,null(默认)
deviceName 测试设备类型(测试Android时被忽略) null(默认)
app 指向APP安装文件,Android中如果设置了appActivity和appPackage,则此会被忽略 null(默认)
browserName 手机网页测试时浏览器的名称 设置为Safari在测iOS和Chrome时,设置为Browser在测Android时
newCommandTimeout Appium服务器等待Appium客户端发送新消息的时间,单位为s 60s(默认)
language (仅模拟器使用)设置模拟器的语言 null(默认)
locale (仅模拟器使用)设置模拟器的使用国家 null(默认)
udid (仅真机使用)测试设备的ID 在多台设备与同一台电脑连接时必须指定
orientation (仅模拟器使用)屏幕方向 LANDSCAPE,PORTRAIT,null(默认)
autoWebview 直接切换到WebView上下文 false(默认),true
noReset 在一个Session开始前不重置被测程序的状态 false(默认),true
fullReset 完全重置(Android通过卸载程序的方式),Session完成后会卸载程序 false(默认),true

~

4.2 仅对Android测试有效的设置

Capability 是否为必填项 描述
appActivity 被测APP启动的Activity名称 如.MainActivity
appPackage 被测APP的包名 例如:com.example.android.myApp
deviceReadyTimeout 等待设备ready的超时时间 5s(默认)
ignoreUnimportantViews 会忽略一些控件,加快运行 false(默认),true
disableAndroidWatchers 只针对基于UIAutomator的测试有效,不会监控ANR和Crash,这将较少CPU消耗 false(默认),true
unicodeKeyboard 是否支持Unicode的键盘,如果输入中文,设置为是 false(默认),true
resetKeyboard 测试结束后是否恢复键盘,为正常的手机键盘 false(默认),true
androidScreenshotPath 截图存放的目录 /data/local/tmp(默认)

~

关于Android测试的Capability非常的多,以上只是其中常用的一部分。还有iOS相关的没有在这里叙述了,有兴趣的可以访问前面给出的官网地址去查看。

五、获取控件

5.1 Native APP

API 方法描述
find_element_by_id(self,id) 通过控件的resource id来查找控件
find_element_by_name(self,name) Native APP中,name就是控件的Text
find_element_by_class_name(self,name) 控件的class name,网页测试也可以用此
find_element_by_accessibility_id(self,id) 控件的accessibility_id就是Content Description
find_element_by_android_uiautomator(self,uia_string) 根据UIAutomator的语法查找控件,是WebDriver在兼容Appium时才新加的语法

~

页面中同一个ID的控件可能不止一个,最常见的就是列表项。find_element_by_id是查找页面中第一个ID为指定参数的控件,find_elements_by_id是查找页面中所有ID为指定参数的控件,返回一个控件列表。其他的查找方法类似。

5.2 Web&Hybrid APP

API 方法描述
find_element_by_xpath(self,xpath) 通过控件的xpath来查找控件
find_element_by_css_selector(self,css_selector) 通过控件的css_selector来查找控件
find_element_by_link_text(self,link_text) 通过链接的text来查找控件
find_element_by_partiallink_text(self,link_text) 通过链接的部分文本来查找控件
find_element_by_tag_name(self,tag_name) 通过网页元素的Tag查找控件

~

这一部分的控件查找和Selenium中的几乎一样,可以查看笔者之前的相关文章。

5.3 获取控件举例

appium find1

下面代码片段为获取图中底部tab的视频按钮的两种方法。第一种用到了name属性,先找到其父控件,进一步缩小范围,因为页面中可能在其他地方也有相同的name。第二种是用find_elements系列的方法,再拿到列表中的第2项,因为下方的几个控件id都是相同的。

self.driver.find_element_by_id('android:id/tabs').find_element_by_name('视频').click() self.driver.find_elements_by_id('com.ss.android.article.news:id/b5e')[1].click()
  • 1

对于一些找不到方法去定位的元素怎么办呢?首先想到的就是坐标定位,为了兼容更多的机型,可以用相对坐标或者距离元素的位置来定位。更高端的方法就是可以采用图像识别来确定要定位的元素,从而进行点击,可以参考这篇文章。http://tmq.qq.com/2017/02/test_guide/

六、操作控件

6.1 获取控件信息(部分)

API 方法描述
text(self) 获取控件显示的文本信息
is_enabled(self) 判断是否可用了,可用返回true
is_selected(self) 是否被选中了,是的话返回true
id_displayed(self) 判断控件是否显示,是的话返回true
get_attribute(self,name) 获取控件某项信息,如element.get_attribute(“displayed”)等同于id_displayed方法
parent(self) 返回控件的父控件,返回值为一个控件对象

6.2 手势操作(部分)

主要有点击、滑动、拖拽、放缩等常用的操作。

API 方法描述
click(self) 点击控件
clear(self) 清楚文本框控件的文本
send_keys(self,*value) 发送文本到控件中
tap(self,positions,duration=None) positions是一个列表,每个列表是一个二元组最多可以同时点击5个点;duration为时间长短,给参数的话则是长按操作
swipe(self,start_x,start_y,end_x,end_y,duration=None) 从一点滑动到另一点,时长为毫秒
flick(self,start_x,start_y,end_x,end_y) 两点快速的滑动
scroll(self,origin_ele,destination_ele) 从origin_ele控件滚动到destination_ele控件
drag_and_drop(self,origin_ele,destination_ele) 把origin_ele控件拖拽到destination_ele控件的位置
pinch(self,element=None,percent=200,steps=50) 在指定控件上执行缩小操作,默认缩放比例为2,分50步完成
zoom(self,element=None,percent=200,steps=50) 在指定控件上执行放大操作,默认缩放比例为2,分50步完成

6.3 系统操作API(部分)

系统操作用于模拟硬件操作、设置网络环境、获取系统信息等,下表简单的介绍一下常用的方法。

API 方法描述
launch_app(self) 启动Capability中指定的APP
is_app_installed(self,package_name) 判断应用程序是否安装
install_app(self,app_path) 安装APP,app_path指的是电脑上的apk路径
close_app(self) 如果Capability指定的APP在运行,则关闭它
background_app(self,seconds) 将APP放到后台运行一段时间
reset(self) 重置当前被测APP到初始状态
current_activity(self) 获取当前正在显示的Activity
start_activity(self,app_package,app_activity,**opts) 启动某个Activity
pull_file(self,path) 拉取手机上的一个文件,并以base64格式编码返回数据,path为手机文件路径
pull_folder(self,path) 拉取手机上的一个文件夹,打包后以base64格式编码返回数据,path为手机上的文件夹路径
push_file(self,path,base64data) 将一个base64编码格式的文件从电脑推送到手机上的路径path上
press_keycode(self,keycode,metastate=None) 模拟发送一个硬件码到手机,如返回等
open_notification(self) 打开通知栏
network_connection(self) 返回当前网络连接的类型
set_network_connection(self,connectionType) 设置网络,值为:0 未设置,1 飞行模式,2 WiFi only, 4 Data only, 6 WiFi& Data
get_screenshot_as_file(self,filename) 截图并保存在电脑上,filename为路径及截图名称
save_screenshot(filename) 截图并保存在电脑上,filename为路径及截图名称

七、控件信息验证

这里我们要说的是查找并操作控件后,怎么确定我们的操作起了作用。在实际的测试中也把它叫做检查点,检查点的划分和验证是UI自动化中的一个重点也是难点。常用的有以下方法:

  1. 判断某个控件是否显示(操作之后新出现的控件)
  2. 判断某个控件是否被选中
  3. 判断某个开关控件是否处于check状态
  4. 判断某个控件是否enabled
  5. 截图之后和正确的进行比对

可以将以上判断的方式进行封装,便于我们在if语句和assert中使用。关于截图对比的方式,首先要有正确的操作截图,然后再进行对比得出结论看看是否一致,会涉及一些算法相关的知识。

八、常见问题

8.1 A new session could not be created

有一次在执行的过程中,发现输出了以下错误;

selenium.common.exceptions.WebDriverException: Message: A new session could not be created. (Original error: An unknown server-side error occurred while processing the command. (Original error: unknown error: com.android.chrome is not installed on device 8c28b78c  (Driver info: chromedriver=2.18.343845 (73dd713ba7fbfb73cbb514e62641d8c96a94682a),platform=Windows NT 10.0 x86_64)))
  • 1
  • 2

可以发现主要的错误应该是com.android.chrome is not installed on device,这个看起来应该是chrome浏览器的手机端,我们可以尝试安装它。但是,我记得手机上一直都没有安装过这个,最后又检查了一下,发现原来是打开了Appium设置中的Browser,关闭此即可。

appium setting

然而,除了这个原因有可能是别的原因,我们要具体分析错误输出,还可以做一些事情来来降低这种情况的发生:

  1. 在初始化的setUp()方法中调用ADB命令强制关闭被测应用一次;
  2. 添加–session-override选项,命令行中或者Appium界面中;
  3. 在tearDown()方法中,关闭Appium的session,清理环境。

8.2 Permission to start activity denied.

在使用start_activity()方法来启动另一个APP时,有时会遇到如下错误:

selenium.common.exceptions.WebDriverException: Message: Unable to launch the app: Error: Permission to start activity denied.

这时可以看到我们没有权限打开这一个Activity,通常是因为此Activity在清单文件里面没添加Android:exported=”true”,exported属性就是设置是否允许activity被其它程序调用的。所以我们需要从启动页Activity打开如下所示。这在一些情况下可能会有点麻烦。

app_package='com.gotokeep.keep'app_activity='.activity.SplashActivity'self.driver.start_activity(app_package,app_activity)
  • 1
  • 2
  • 3

还有一种错误是找不到要打开的Activity:

elenium.common.exceptions.WebDriverException: Message: Unable to launch the app: Error: Activity used to start app doesn’t exist or cannot be launched! Make sure it exists and is a launchable activity

这时我们要检查Activity是否存在,并且路径是否填写正确。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多