Appium测试概览
什么是Appium:
自动化测试开源工具,支持 iOS/Android 平台的原生应用,web应用和混合应用。
移动原生应用是指那些用iOS或者 Android SDK 写的应用。
移动web应用”是指使用移动浏览器访问的应用。
混合应用是指原生代码封装网页视图——原生代码和 web 内容交互。
Appium的特点:
appium是一个跨平台的工具:允许测试人员在不同的平台(iOS,Android)使用同一套API来写自动化测试脚本,增加iOS和Android测试套件间代码的复用性。
appium类库封装标准Selenium客户端类库,为用户提供所有常见的JSON格式selenium命令以及额外的移动设备控制相关的命令,如多点触控手势和屏幕朝向。
appium选择Client/Server的设计模式。只要client能够发送http请求给server,那么的话client用什么语言来实现都是可以.
Appium生态工具:
Appium Desktop:内嵌Appium Server和Inspector的综合工具
Appium Server :Appium的核心工具,命令行工具.
Appium Clients:各种语言的客户端封装库,用于连接appium server.Appium Crawler自动遍历工具
Appium实现原理:
它属于 C/S 架构,Appium Client 通过第三方库向 Appium Server 发起请求,Appium Server 接受请求,然后和移动平台上的代理工具打交道,代理工具在运行过程中不断接收来自 Appium Server 的请求,并解析出要执行的操作,最后调用移动平台原生的测试框架完成测试操作.
Appium也是利用WebDriver来实现App的自动化测试。对iOS设备来说,Appium使用UIAutomation来实现驱动。对于Android来说,它使用UiAutomator和Selendroid来实现驱动。
Win10环境搭建:
Win10环境变量分为系统环境变量和用户环境变量。通常所说的环境变量是指系统环境变量,对所有用户起作用 。而用户环境变量只对当前用户起作用。
1.安装 jdk,一路傻瓜式安装,注意安装路径不要有空格,不要有中文。jdk和jre不要放在一个文件夹下.
然后配置环境变量:
设置三个环境变量,我的电脑>选择“属性”->“高级”->“环境变量”->“系统变量”->“新建”
(1)JAVA\_HOME----D:\\software\\Java\\jdk1.8.0\_181” (根据自己安装路径填写)
(2)CLASSPATH--- .;%JAVA\_HOME%\\lib;%JAVA\_HOME%\\lib\\tools.jar;
(3)PATH-----;%JAVA\_HOME%\\bin;%JAVA\_HOME%\\jre\\bin;
打开cmd验证是否安装成功,输入java -version,然后输入javac
2.安装 npm install -g appium(Appium Server安装),先安装nvm,再设置切换node和npm的源,在切换npm为淘宝源.
3.安装 android studio 开发工具,配置环境变量.
在系统变量新建:ANDROID\_HOME,对应变量值为:D:\\software\\android-sdk-windows(sdk安装路径)
path添加两个变量,将以下箭头所指的两个文件路径(platformsy与tools)添加到path里
4.安装npm install -g appium-doctor 查看环境配置有无问题.
5.安装Python与pip3 install Appium-Python-Client
Python多版本隔离工具选env,测试框架有unittest,pytest,nose.选pytest.
Appium Desktop安装:官网下载安装: https://github.com/appium/appium-desktop/releases
5.nvm安装:略.安装安装.net framework http://www.microsoft.com/zh-cn/download/details.aspx?id=30653
6.安装Webdriver:略.
7.appium-doctor安装,检查以上所有配置是否成功.
以Android Studio启动youtube为例.
配置待测应用以启动appium:以Android Studio的模拟器的youtube为例,配置如下,进行启动.
{
"platformName": "android",
"deviceName": "bluestack",
"appPackage": "com.google.android.youtube",
"appActivity": "com.google.android.apps.youtube.app.WatchWhileActivity",
"autoGrantPermissions": true
}
夜神模拟器配置:
(1)官网下载,修改文件安装目录.一键下载.
(2)配置系统环境:在Path中添加D:\software\nox\Nox\bin; (模拟器安装的bin目录).
(n)补写一下魅族手机的链接,注意点击手机的版本号,多次点击打开开发者模式后,去开发者模式里面打开USB调试.
Appium-Server:
配置要打开的app,连接模拟器,进行控制,进行UI分析,点击顶部的选择元素进行元素分析,录制简单测试用例且保存.
点击开始录制,选择代码方式,展开样式代码进行操作,操作完成后,保存代码.
uiautomatorviewer:
(1)在Android SDK中的tools中有一个uiautomatorviewer.bat
(2)启动后点击左上角第三个图标进行真机界面的呈现,选择真机.
ADB命令
连接设备
adb shell
adb connect 127.0.0.1:7555
adb shell
获取 App 的信息
# app信息
# 获取当前界面元素
adb shell dumpsys activity top
# 获取任务列表
adb shell dumpsys activity activities
# App 入口
adb logcat | grep -i displayed
aapt dump badging moblike.apk | grep lanunchable-activity
apkanalyzer 最新版本的 sdk 中才有
# 启动应用
adb shell am start -W -n com.xueqiu.android/.view.WelocmeActivityAlias -S
Android 常用命令
# 查看设备
adb devices
# 关闭 adb 的后台进程
adb kill-server
# 让 Android 设备脱离 USB 线的 TCP 连接方式
adb tcpip 127.0.0.1:7555
# 连接开启了 TCP 连接方式的 Android 设备
adb connect 127.0.0.1:7555
# 查看 Android 日志查看
adb logcat
# 收集日志数据,用于后续的分析,比如耗电量
adb bugreport
常用API
基本demo
# This sample code uses the Appium python client
# pip install Appium-Python-Client
# Then you can paste this into a file and simply run with Python
from appium import webdriver
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "bluestack"
caps["appPackage"] = "com.google.android.youtube"
caps["appActivity"] = "com.google.android.apps.youtube.app.WatchWhileActivity"
caps["autoGrantPermissions"] = True
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
#添加隐式等待
driver.implicitly_wait(1)
"""
#增加TouchAction
TouchAction(driver).long_press().move_to().release().perform();
driver.swipe()
"""
el1 = driver.find_element_by_xpath("//android.widget.Button[@content-desc=\"Subscriptions\"]/android.widget.ImageView")
el1.click()
el2 = driver.find_element_by_xpath("//android.widget.Button[@content-desc=\"Library\"]/android.widget.ImageView")
el2.click()
el3 = driver.find_element_by_accessibility_id("Search")
el3.click()
el4 = driver.find_element_by_id("com.google.android.youtube:id/search_edit_text")
el4.click()
el4.send_keys("wuhong")
driver.quit()
Pytest的demo
#PyTest模板用例
#引入***
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
class TestDemo:
def setup(self): #driver初始化
caps = {}
caps["platformName"] = "android"
caps["deviceName"] = "bluestack"
caps["appPackage"] = "com.google.android.youtube"
caps["appActivity"] = "com.google.android.apps.youtube.app.WatchWhileActivity"
caps["autoGrantPermissions"] = True
self.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
self.driver.implicitly_wait(1)#添加隐式等待
def test_demo(self): #用例部分
el1 = self.driver.find_element_by_xpath("//android.widget.Button[@content-desc=\"Subscriptions\"]/android.widget.ImageView")
el1.click()
el2 = self.driver.find_element_by_xpath("//android.widget.Button[@content-desc=\"Library\"]/android.widget.ImageView")
el2.click()
el3 = self.driver.find_element_by_accessibility_id("Search")
el3.click()
el4 = self.driver.find_element_by_id("com.google.android.youtube:id/search_edit_text")
el4.click()
el4.send_keys("wuhong-CCC")
#添加设备交互
def test_gsm_call(self):
self.driver.send_sms("123131233","Hello,Form Linyi")
#self.driver.make_gsm_call("12321312",GsmCallActions.CALL)
def test_performance(self):
print(self.driver.get_performance_data_types())
for p in self.driver.get_performance_data_types():
try:
print(self.driver.get_performance_data("com.google.android.youtube",p,5))
except:
pass
def teartdown(self):
self.driver.quit()
查找元素
使用Selenium中通用的查找方法来实现元素的查找,其他方法不再累述.如下所示:
el = driver.find_element_by_id('com.tencent.mm:id/cjk')
在Android平台上,可以使用UIAutomator来进行元素选择,如下所示:
el = self.driver.find_element_by_android_uiautomator('new UiSelector().description("Animation")')
els = self.driver.find_elements_by_android_uiautomator('new UiSelector().clickable(true)')
在iOS平台上,可以使用UIAutomation来进行元素选择,如下所示:
el = self.driver.find_element_by_ios_uiautomation('.elements()[0]')
els = self.driver.find_elements_by_ios_uiautomation('.elements()')
还可以使用iOS Predicates来进行元素选择,如下所示:
el = self.driver.find_element_by_ios_predicate('wdName == "Buttons"')
els = self.driver.find_elements_by_ios_predicate('wdValue == "SearchBar" AND isWDDivisible == 1')
也可以使用iOS Class Chain来进行选择,但是此种方法只适用于XCUITest驱.如下所示:
el = self.driver.find_element_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton[3]')
els = self.driver.find_elements_by_ios_class_chain('XCUIElementTypeWindow/XCUIElementTypeButton')
点击
tap()
方法,可以模拟手指点击(最多五个手指),可设置按时长短(毫秒).tap(self, positions, duration=None)
positions
:它是点击的位置组成的列表. duration
:它是点击持续时间
#实例一,模拟点击屏幕的某几个点
driver.tap([(100, 20), (100, 60), (100, 100)], 500)
#对于某个元素如按钮来说,我们可以直接调用cilck()方法实现模拟点击
button = find\_element\_by\_id('com.tencent.mm:id/btn')
button.click()
屏幕拖动
scroll()
方法模拟屏幕滚动.可以实现从元素origin_el
滚动至元素destination_el
。scroll(self, origin_el, destination_el)
original_el
:它是被操作的元素。 destination_el
:它是目标元素。
driver.scroll(el1,el2)
swipe()
方法模拟从A点滑动到B点.swipe(self, start_x, start_y, end_x, end_y, duration=None)
-
start_x
:它是开始位置的横坐标。 -
start_y
:它是开始位置的纵坐标。 -
end_x
:它是终止位置的横坐标。 -
end_y
:它是终止位置的纵坐标。 -
duration
:它是持续时间,单位是毫秒
#在5s时间内,由(100, 100)滑动到 (100, 400)
driver.swipe(100, 100, 100, 400, 5000)
flick()
方法模拟从A点快速滑动到B点.flick(self, start_x, start_y, end_x, end_y)
-
start_x
:它是开始位置的横坐标。 -
start_y
:它是开始位置的纵坐标。 -
end_x
:它是终止位置的横坐标。 -
end_y
:它是终止位置的纵坐标。
driver.flick(100, 100, 100, 400)
拖曳
drag_and_drop()
将某个元素拖动到另一个目标元素上.drag_and_drop(self, origin_el, destination_el)
可以实现将元素origin_el
拖曳至元素destination_el
。
-
original_el
:它是被拖曳的元素。 -
destination_el
:它是目标元素。
driver.drag_and_drop(el1, el2)
文本输入
set_text()
方法实现文本输入
el = find_element_by_id('com.tencent.mm:id/cjk')
el.set_text('Hello')
动作链
与Selenium中的ActionChains类似,Appium中的TouchAction可支持的方法有tap()
、press()
、long_press()
、release()
、move_to()
、wait()
、cancel()
等,实例如下所示:
el = self.driver.find_element_by_accessibility_id('Animation')
action = TouchAction(self.driver)
action.tap(el).perform()
如果想要实现拖动操作,可以用如下方式:
els = self.driver.find_elements_by_class_name('listView')
a1 = TouchAction()
a1.press(els[0]).move_to(x=10, y=0).move_to(x=10, y=-75).move_to(x=10, y=-600).release()
a2 = TouchAction()
a2.press(els[1]).move_to(x=10, y=10).move_to(x=10, y=-300).move_to(x=10, y=-600).release()
增加隐式等待:driver.implicitly_wait(10)
隐式等待:服务端(appium)会在特定超时时间内重试多次寻找控件. 显示等待:在客服端(用例端)根据更灵活的条件循环等待条件满足.
在VSCode运行:$sppium后,直接在IDE运行.
测试步骤三要素:定位,交互,断言.
常用定位手段: id, Accessibility ID, XPath(XML路径语言,用于XML中的节点定位)
App DOM:关键Attribute的clickble,content-desc,resource-id,text,bounds,其中android与ios的DOM属性与节点结构类似,名字和属性的命名不同.
元素定位符与复用:findElementByxxx,findElement(by,value),findElement主要用于 Page Object模式.
常用自动化动作支持: click,sendkys,swiper,touch action
手势操作: Press release longPress, moveTo,tapwait,perform
使用测试框架管理测试用例:Java的Unit4,Junit5,TestNG. Python的unittest和pytest
设备交互API:模拟电话,短信,横竖屏切换,app处理,键盘,粘贴板,录屏.
显示等待:显示等待的条件非常灵活,隐式等待只能用于元素定位,显示等待本地轮询条件,隐式等待通过appium server轮询条件.(三种方式,代码文件只整理了一种.)
Xpath定位: 绝对定位是根据严格的父子关系定位,相对定位根据条件匹配定位,但Xpath定位比其他定位慢,因为需要递归解析每个元素的属性,或是Cache机制.最好使用相对定位,以下是一些相对定位方式:
查找: //*[@text=’登录’] 或//*[contains(@resource-id,’login’)]
条件匹配: //*[contains(@resource-id,’login’)and contains(@text,’登录’)]
寻找所有元素: //%
AndroidToast识别:
识别方法:必须使用xpath查找,可用uisutomator2,推荐使用//*[@class=’android.widgest.Toast’]或是//*[contains(@text,”xxx”)]
断言内容: assert xx
元素是否存在: find_elements 元素属性正确性:get_attribute
Assert ‘price’ in price.get_attribute(“resource-id)
xUnit常用断言类型:传统风格的xUnit风格的assertXXX()系列.Hamcrest断言采用更灵活的Matchers断言方式.
参数化与数据驱动:
参数化:根据传入的数据,对测试用例进行迭代调用.数据驱动:基于数据完成流程调度,通常数据来源自外部数据文件,
参数化是数据驱动的基础和特例.
Page Object Model:
做法:以页面为单位独立建模,隐藏实现细节,本质是面向接口编程.优点在减少重复find click样板代码,易读性提高,页面修改不影响测试用例.
参考
(1):Appium配置模拟器
(2):掘金博客