欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Appium自动化测试-入门

程序员文章站 2022-07-12 18:39:21
...

一、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://appium.io/

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

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

Appium自动化测试-入门

Appium自动化测试-入门

三、编写脚本前的准备

3.1 查看页面元素

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

Appium自动化测试-入门

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

Appium自动化测试-入门

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

Appium自动化测试-入门

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

3.2 相关文档

这个网站上说明了Appium的方方面面,如设计理念、各个平台的安装、脚本编写等等。http://appium.io/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.结果验证

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

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

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

四、Desired Capabilities说明

Desired Capabilities就是一组设置,这些设置可以让测试脚本控制Appium的运行行为。下面对这些设置做一个简单的说明。从其官方网站我们可以得到全面的信息,网址为:http://appium.io/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自动化测试-入门

下面代码片段为获取图中底部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()

对于一些找不到方法去定位的元素怎么办呢?首先想到的就是坐标定位,为了兼容更多的机型,可以用相对坐标或者距离元素的位置来定位。更高端的方法就是可以采用图像识别来确定要定位的元素,从而进行点击,可以参考这篇文章。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)))

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

Appium自动化测试-入门

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

  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)

还有一种错误是找不到要打开的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是否存在,并且路径是否填写正确。