1、背景
最近开始写UI自动化测试用例,发现很多UI自动化知识不用的时候很容易遗忘,使用的时候又需要快速捡起,在回顾的过程中把相关知识总结整理了出来,希望作为一个小小的知识百科分享,方便快速查阅。
2、Appium工作原理
- Appium的核心其实就是一个暴露了一系列REST API的server
- 这个server的功能很简单:监听一个端口(4723),接收由客户端发送过来的命令command,翻译这些command
- 把这些command转换成移动设备可以理解的形式发送给移动设备,调用设备上内置的自动化框架api去执行操作
- 移动设备执行完这些command后把执行结果返回给appium server,最后Appium server再把执行后的结果返回给client客户端
2.1 手机端运行原理如下
- appium使用adb向手机/模拟器部署Bootstrap.jar
- Bootstrap.jar接收appium发过来的指令
- Bootstrap.jar再次将命令发给uiautomator
- uiautomator再次执行命令
2.1.1 一个完整的请求过程
- 收到http请求
- 创建会话
- 确认当前是否有连接的设备,并且确认是否匹配安卓版本
- 确认设备上有没有指定包名的app
- 往设备上安装appium自己的 setting apk包。若已安装,需要确认apk版本是否匹配。
- appium会往设备上推送一个appiumbootstrap.jar包。–java代码
运行jar包,在手机上启动一个ip+端口。接收来自appium server的请求,调用手机上的自动化框架执行操作。
2.1.2 建立连接完整步骤
准备工作:
- 启动appium程序
- 至少有一个设备是能够识别到的 adb devices
- 获取应用包名appPackage和appActivity
2.2 aapt命令:apk获取应用包名appPackage和appActivity
-
aapt
目录:/adt-bundle-mac-x86_64-20140624/sdk/build-tools/android-4.4W/aapt
- 命令用法:
aapt dump badging apk应用名
- 示例:
aapt dump badging D:\BaiduNetdiskDownload\Future-release-2019.apk
-
launchable activity
后就是appActivity
2.2.1 准备启动参数:告诉appium,要打开哪个设备上的哪个app
原理:
-
appium desktop
服务同时支持android
和ios
,android
和ios
有自带的自动化框架 -
Android
和iOS
有很多的版本且版本之间存在自动化框架上的差异,所有代码当中必须告诉appium
- 你是要在 哪个平台的哪个版本上,对哪个app进行操作。
启动参数获取地址:http://appium.io/docs/en/writing-running-appium/caps/#general-capabilities
- 1.告诉平台
android
/ios
- 2.系统版本号
- 3.设备名称 需要这个参数但是没有实际用处
- 4.包名
- 5.
appActivity
入口页面 - 6.
noReset
:不重置应用的数据,假如现在已经登录上app
.如果是noReset=false
,那么appium
执行的时候会将应用的数据清除,反之noReset=true
,appium
执行时候不会清掉数据进行测试。默认是noReset=false
2.2.2 启动appium server程序 查看端口号
2.2.3 连接appium server,把端口替换为appium启动后的端口号,开启appium server
2.2.4 运行代码
3、Appium安装五大件
appium desktop http://appium.io
-
appium-python
库pip install Appium-Python-Client
- ADT工具包 安装
AndroidStudio
版本然后配置环境变量
参考此篇文章 - 模拟器/真机 真机需要在开发者选项中开启USB调试模式
-
JDK
安装JDK1.8
,配置环境变量
4、app元素定位三个工具
元素定位出错后我们首先要检查:
-
adb
能识别到设备吗 - 定位时设备有被其他程序占用吗(即便是
appium server
在占用也不可以,必须等appium server
停止运行才可以定位到) - ADT的版本正确吗
5、每一种工具正确定位的前提:
- 通过 adb devices命令能够识别到至少一个android设备;
- 设备当前没有被任何其它的应用程序所占用;
5.1 第一种:python版uiAutomator2中的weditor
python语言实现的一个app自动化测试框架。
安装
安装uiAutomator2:pip install -U uiautomator2
初始化命令(往手机上推送apk包):python -m uiautomator2 init
安装定位工具weditor: pip install -U weditor
安装完成之后:命令行运行:weditor --help确认是否安装成功。
使用
- 命令行输入:python -m weditor 会自动打开在浏览器当中打开一个页面
- 选择Android,输入设备序列号,点击connect。点击Dump Hierarchy,就可以看到元素的信息了。
- 如果xpath定位使用了sourceid代表sourceid是唯一的可以直接用find_element_by_id
5.2 第二种:android ADT自带工具:uiAutormatorViewer
android 4.2
以上的版本,自带的自动化测试框架是uiAutomator
。uiAutomatorViewer
就是它的元素定位工具了
缺点
不支持jdk1.8以上的版本。所以为了启动成功,要安装jdk1.8的版本。
mac下若安装了jdk11和jdk1.8,需要编辑uiautomatorviewer
文件,找到javaCmd="java"
,
修改为 javaCmd="/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java"
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java
为jdk1.8版本对应的java
安装:
uiAutomatorViewer
是安卓调试工具(ADT)中的一部分。所以只需要安装ADT就可以了(不需要安装SDK哦)。
- 安装
Android Studio
- 在
Android Studio
的启动页面当中,选择右下角的Configure
->SDK Manager
会弹出下图:选择Android SDK
->SDK Tools
,按图中勾选,点击OK进入安装,安装完成即可关闭Android Studio
。 记住图中Android SDK Location
对应
使用
- 找到
ADT
安装目录,在其tools/bin
目录下,找到uiAutomatorViewer
程序,双击打开。
例如:ADT
的目录为:/Users/liyuan/Library/Android/sdk/tools/bin
- 定位元素
5.3 第三种:appium的appium inspector
appium
是目前最流行的开源的app
功能测试框架。
同时支持IOS
和Android
的自动化测试,也支持多语言(python/java/C#…)
安装
只要安装appium
,那么appium inspector
也就有了。appium desktop
下载地址:http://appium.io/
使用
- 启动appium desktop之后,点击右上角的第一个按钮
- 在打开如下界面当中,按图中所示,填写信息
- 会根据启动参数,去打开对应的app,然后会截取app当中的页面
总结
以上3种定位告诉你: 任何一个app自动化测试的框架,都会给你提供一个对应的定位工具哦!android
自带的UiAutomator
测试框架,提供 uiAutomatorViewer
。appium
测试框架,提供appium inspector
.python
实现的uiAutomator2
测试框架,提供weditor
在app自动化测试的过程中,可以使用任意一种或多种来帮你进行元素定位。 推荐使用第一种
6、元素六大定位方式
7、元素常用六大操作
7.1 模拟滑屏上拉下拉操作 TouchAction swipe
元素行为
tap屏幕点击 press 按住屏幕 long_press 长按 release 释放 move_to 从一个点移动到另一个店 wait等待
元素操作 perform()
from appium.webdriver.common.touch_action import TouchAction
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 1.准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage":"com.dewu.com",
"appActivity":"com.dewu.activity.WelcomeActivity",
"noReset":True
}
# 2.、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
# 3.元素定位 使用ID定位方式
loc = (MobileBy.ID,'com/navigation_tiku')
# 4.等待 - 3大等待方式
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
# 5.点击进入题库界面
driver.find_element(*loc).click()
# 等待所有题库都出来了,再滑动
time.sleep(6)
# 1.获取整屏的大小 size返回一个字典{width,height}
size = driver.get_window_size()
# 2.按压屏幕从一个点移动到另一个点
driver.swipe(size["width"]*0.5,size["height"]*0.9,size["width"]*0.5,size["height"]*0.3,200)
7.2 页面滑动多次寻找某个页面的某一个元素点击 swipe
from appium.webdriver.common.touch_action import TouchAction
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 1.准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage":"com.xxx",
"appActivity":"com.xx.activity.WelcomeActivity",
"noReset":True
}
# 2.、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
# 3.元素定位
loc = (MobileBy.ID,'com.xx/navigation_tiku')
# 4.等待 - 3大等待方式
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
# 5.点击 进入题库界面
driver.find_element(*loc).click()
# 6.等待所有题库都出来了,再滑动
time.sleep(3)
# 1、获取整屏的大小
size = driver.get_window_size()
# 循环/滑动
# 什么时候滑?滑几次?滑到什么时候终止?滑到底部了如何不再滑动?
# 滑动以前的内容 != 滑动以后的内容 => 继续滑
# 滑动以前的内容 == 滑动以后的内容 => 已经到底部
"""
# 滑动以前的内容
old = None
# 滑动后的内容
new = driver.page_source
while 滑动以前的内容 != 滑动以后的内容:
如果元素找着了(driver.find_element()/page_source.find()):
break
如果没找着:
滑动操作 -
sleep(3)
old = new
new = driver.page_source
"""
# 滑动以前的内容
old = None
# 返回新页面源码
new = driver.page_source
while old != new:
try:
# 通过android uiatumator的UiSelector类查询名为安全测试的元素
driver.find_element_by_android_uiautomator('new UiSelector().text("安全测试")')
except:
# 在200ms内从中心屏幕高度90%的地方滑到屏幕高度30%的地方
driver.swipe(size["width"]*0.5,size["height"]*0.9,size["width"]*0.5,size["height"]*0.3,200)
time.sleep(3)
old = new
# 重新获取页面源码
new = driver.page_source
else:
print("找到了安全测试")
break
7.3 多点触控 multi_action
实现了多个单点触控,同时执行**
- add 添加单点触控的行为
- 2.perfrom 执行
百度地图放大
from appium.webdriver.common.multi_action import MultiAction
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from appium.webdriver.common.touch_action import TouchAction
# 1.准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage": "com.baidu.BaiduMap",
"appActivity": "com.baidu.baidumaps.WelcomeScreen",
"noReset":True
}
# 2.、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
time.sleep(15)
# 3.、获取整屏的大小
size = driver.get_window_size()
# 4.实例化 TouchAction对象
a = TouchAction(driver)
# 5.一个点从屏幕中心位置移动到屏幕右下角
a.press(x=size["width"]*0.5,y=size["height"]*0.5).wait(200).move_to(x=size["width"]*0.1,y=size["height"]*0.9).release()
# 6.一个点从屏幕中心向右上角滑动
b = TouchAction(driver)
b.press(x=size["width"]*0.5,y=size["height"]*0.5).wait(200).move_to(x=size["width"]*0.9,y=size["height"]*0.1).release()
# 7.加入Multiaction
ma = MultiAction(driver)
ma.add(a,b)
ma.perform()
7.4 tap
最多用5根手指点击一个地方
用法:传一个嵌套元祖的列表。为点的坐标driver.tap([(100, 20), (100, 60), (100, 100)], 500)
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
from appium.webdriver.common.touch_action import TouchAction
# 1\准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage": "com.baidu.BaiduMap",
"appActivity": "com.baidu.baidumaps.WelcomeScreen",
"noReset":True
}
# 3、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
driver.tap()
7.5 toast
处理
- toast只能用ui automator2来处理
- appium server1.15以上版本自动为uiautomtor2, 低于这个版本需要指明"automationName":“UiAutomator2”
- toast只有文本,只支持xpath定位, //*[contains(@text,“手机号码”) 不能够用等待元素可见,只能用元素存在否则会报错
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 1\准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage":"com.xx",
"appActivity":"com.xx.activity.WelcomeActivity",
"noReset":True
}
# 3、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
loc = (MobileBy.ID,"com.xx:id/navigation_my")
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
driver.find_element(*loc).click()
loc = (MobileBy.ID,"com.xx:id/fragment_my_lemon_avatar_layout")
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
driver.find_element(*loc).click()
loc = (MobileBy.ID,"com.xx:id/btn_login")
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
driver.find_element(*loc).click()
# xpath表达式
loc = (MobileBy.XPATH,'//*[contains(@text,"手机号码或密码")]')
try:
# 等待元素存在
# 短期内就会消失的,要缩小巡查周期
WebDriverWait(driver,6,0.01).until(EC.presence_of_element_located(loc))
# 获取文本
text = driver.find_element(*loc).text
print(text)
except:
print("我没有获取到toast的提示信息!!")
7.6 应用切换 driver.start_activity
(包名,应用名)
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
# 1\准备参数:告诉appium,你要打开哪个设备上的哪个app。
desired_caps = {
"automationName":"UiAutomator2",
"platformName":"Android",
"platformVersion":'7.1.2',
"deviceName":"emulator-5554",
"appPackage":"com.xx",
"appActivity":"com.xx.activity.WelcomeActivity",
"noReset":True
}
# 3、连接appium server,把启动参数发送
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
loc = (MobileBy.ID,"com.xx/navigation_my")
WebDriverWait(driver,20).until(EC.visibility_of_element_located(loc))
driver.find_element(*loc).click()
# 传包名和应用名
driver.start_activity("com.baidu.BaiduMap","com.baidu.baidumaps.WelcomeScreen")