一、Appium****的介绍
Appium是一款开源的自动化测试工具,支持模拟器和真机上的原生应用、混合应用、Web应用;基于Selenium二次开发,Appium支持Selenium WebDriver支持的所有语言(java、 Object-C 、 JavaScript 、p hp、 Python等,Appium支持任何一种测试框架,
二、Appium架构
Appium 是一个用Node.js编写的HTTP server,它创建、并管理多个 WebDriver sessions 来和不同平台交互,如 iOS ,Android等等.
Appium 开始一个测试后,就会在被测设备(手机)上启动一个 server ,监听来自 Appium server的指令. 每种平台像 iOS 和Android都有不同的运行、和交互方式。所以Appium会用某个桩程序"侵入"该平台,并接受指令,来完成测试用例的运行
三、Appium****的工作原理
Client端发送自动化指令给Appium server,Appium Server接收到client发送的指令后,转换为移动端能够识别的ADB指令,然后发送给移动端设备,并对移动端设备进行操作。
【工作过程】
脚本请求 --> 4723端口appium server ---> 解析参数给PC端4724端口 ---> 发送给设备4724端口 ---> 通过设备4724端口发给bootstrap.jar ---> Bootstrap.jar把命令发给uiautomator
注意: Bootstrap.jar :是 push 到 Android 手机上的一个应用程序,主要是接受 Appium Server 的执行并 运行这些测试指令。而指令的执行正是通过UIAutomator 来驱动的。
三、Appium环境搭建
使用appium服务需要配置依赖环境,以及各个环境之间的版本需要互相兼容;
我目前使用的版本信息:
# JDK版本
jdk-8u261
# android SDK版本installer_r24.4.1-windows.exe
# appium客户端Appium-windows-1.15.1.exe
# Appium-Python-Clientpip install Appium-Python-Client==2.11.1
# selenium版本
selenium==4.21.0
# 模拟器nox_setup_v7.0.2.7_full.exe
网盘获取:
链接:https://pan.baidu.com/s/18uqZfmX9d9HqqSBIEM73uA?pwd=z5ak
提取码:z5ak
3.1、配置jdk环境
详见JDK配置文章:
Windows配置java环境JDK-CSDN博客
3.2、android SDK环境
详见SDK配置文章:
Android SDK下载安装(_指定版本)-CSDN博客
3.3、安装appium客户端
Appium安装除了安装Appium客户端,还要在Python环境中安装Appium-Python-Client,其作用就是将 Python 与 appium 关联起来;
**需要指定版本:**pip install Appium-Python-Client==2.11.1
详见Appium配置文章:
Appium安装及配置(Windows环境)-CSDN博客
3.5、下载模拟器
详见模拟器配置文章:
Android模拟器下载及配置_夜神模拟器-CSDN博客
四、启动App
操作步骤:
- 启动桌面Appium客户端
- 启动模拟器或移动设施(确保连接adb)
- 启动Python脚本
4.1、启动桌面Appium客户端
双击 桌面Appium客户端-->启动服务器
4.2、启动模拟器或移动设施(确保连接adb)
ADB命令: ADB日常使用命令-CSDN博客
启动模拟器后,一般默认会已经连接adb,如果没有连接需要输入adb命令进行连接
bash
# 验证是否连接成功
adb devices
# 建立连接
adb connect 127.0.1: 模拟器端口号〈逍遥模拟器21503〉
已连接
4.3、运行Python脚本,启动App
启动参数:
python
# 1.导入appium中的webdriver
from appium import webdriver
import time
def startUp():
print('准备启动app')
# 2. 启动参数,配置手机连接的参数内容,
# 所有参数信息都是键值对的方式进行连接
desire_caps = {
"deviceName": "127.0.0.1:62001", # 参数1:当前设备的名称
"platformName": "Android", # 参数2:系统
"platformVersion": "7.1.2", # 参数3:系统版本号
"appPackage": "com.android.contacts", # 参数4:启动的app名称(包名)
"appActivity": ".activities.PeopleActivity t12", # 参数5:app界面名称
"noReset": True,
"unicodeKeyboard": True
}
# 3.发送连接请求
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desire_caps)
# 等待时间,防止启动后立马关闭
time.sleep(4)
# 关闭驱动
driver.quit()
if __name__ == '__main__':
startUp()
启动参数说明
待补充
五、元素定位工具
Android SDK 自带的一个工具,在 sdk 的 tools 目录下(一定关闭 appium-desktop 的自带的定位工具后打 开,否则连接不上模拟器/ 真机 )
找到 sdk 下的 tools 里面的 uiautomatorviewer.bat
详见uiautomatorviewer.bat使用文章:
appium元素定位工具_uiautomatorviewer.bat-CSDN博客
六、元素定位
6.1、单个元素定位:find_element
语法:
# 需要导包
from selenium.webdriver.common.by import By# 用法 -- 传递两个参数:一个是定位属性,一个是该属性的值
driver.find_element(By. 属性 ,' 属性值 ').操作方法
1.通过id定位
resource-id 的值为id
driver . find_element ( By . ID , " xxxx " )
2.通过class_name定位
取class的属性值
driver . find_element ( By . CLASS_NAME , " xxxx " )
3.通过link_text定位
取 text 属性值--文本属性
driver . find_element ( By . LINK_TEXT , " xxxx " )
4.通过xpath定位
取元素xpath路径
driver . find_element ( By . XPATH , " xxxx " )
# 使用文本属性比较实用(推荐)driver.find_element(By.XPATH, '//*[@text="显示"]').click()
driver.find_element(By.XPATH, '//*[@text="亮度"]').click()
5.通过坐标定位driver.tap()
通过坐标定位有一定的局限性
-
优先:任意的元素都可以通过坐标进行定位操作
-
缺点:当手机的分辨率发生变化的时候,元素的坐标值也会发生变化
注意点:通过坐标定位的方法,一般使用场景是固定的机型或者固定的分辨率下进行自动化测试
driver.tap()
左边通过[(x,y)]形式传入
duration:表示触碰时间/ms
# 左上角
driver.tap([(144,1327)], duration=100)
# 右下角
driver.tap([(208, 1370)], duration=100)
6.2、多个元素定位find_elements
与 find_element 方式基本一致,这个方法可以同时定位多个元素,返回一个列表
例如:通过 ID 定位到多个元素,我想点击第一个元素
driver . find_elements ( By . ID , "xxxxx" )[ 0 ]. click ()
或
list1 = driver . find_elements ( By . ID , "xxxxx" )
list1 [ 0 ]. click ()
七、元素操作方法
Appium元素的操作方法与Selenium元素操作方法,基本一样
1. click():点击
python
# 模拟鼠标点击操作
driver.find_element(By.ID," xxxx ").click()
2. clear():清空
python
# 清空元素输入框中内容
driver.find_element(By.ID," xxxx ").clear()
3. send_keys():输入
python
# 往输入框中,输入内容值
driver.find_element(By.ID," xxxx ").send_keys("输入的内容")
4. text:获取文本属性值
python
# 获得元素的text内容
result = driver.find_element(By.XPATH," xxxx").text
print(result)
5. get_attribute():获取某个标签,元素的属性
python
# 获取标签xxx的元素的 class 属性值
driver.find_element(By.ID,'xxx').get_attribute('class')
6. size:获取元素的大小(宽、高)
python
# 获取元素的大小,得到一个字典如:{'height': 48, 'width': 640}
driver.find_element(By.ID,' xxxx ').size
7. **location:**获取元素的坐标
python
# 获取元素的坐标,得到的是一个字典{}
res = driver.find_element(By.ID,' xxxx ').location
print(res) # {'x': 108, 'y': 380}
8. **is_selected():**判断元素是否被选中
python
# 选中返回True,否则返回False
res = driver.find_element(By.ID, 'xxxx').is_selected()
print(res) # True/False
9. **is_enabled():**判断元素是否被启用
python
# 判断元素是否被启用,返回True / False
res = driver.find_element(By.ID, 'xxxx').is_enabled()
print(res)
10. **is_displayed():**判断元素是否显示
python
#判断元素是否显示,返回True / False
res = driver.find_element(By.ID, 'xxxx').is_displayed()
print(res)
八、其它操作
8.1、操作应用包
1、判断是否安装
python
# 语法 返回True/False
driver.is_app_installed("应用的包名")
# 可以简单做一个判断,然后进行安装或卸载
if driver.is_app_installed('io.manong.developerdaily'):
driver.remove_app('io.manong.developerdaily')
print('app卸载成功')
else:
driver.install_app(r'D:\MS_App_auto_24_529\toutiao.apk')
print('app安装成功')
2、安装应用
python
install_app("app的绝对路径")
3、卸载应用
python
remove_app("应用的包名")
4、获取当前操作的应用的界面名称
current_activity
5、获取包名
driver.current_package
8.2、操作屏幕页面
1.获取屏幕尺寸
方法:driver.get_window_size
python
# 得到的是一个字典,width是屏幕的宽度,height为屏幕的高度
dic = driver.get_window_size()
print(dic ) #{'width': 1080, 'height': 1776}
2.页面滑动
app界面为了保证内存优化性,所有可操作的元素只是当前界面存在的元素,所以需要滑动屏幕,进行元素定位
方式1:坐标定位.swipe()
方法 : driver.swipe(x1, y1, x2, y2,duration)
参数:
(x1, y1):开始坐标,(x2, y2):结束坐标,duration:滑动时间
注意 :滑动的坐标不能超过屏幕的宽高
**实现思路1:**通过 driver.get_window_size() 获得窗口高和宽 -->按比例滚动
python
# 获取屏幕尺寸得到所用坐标
def getSize(driver):
x = driver.get_window_size()['width']
y = driver.get_window_size()['height']
x1 = x * 0.75
x2 = x * 0.25
y1 = y * 0.75
y2 = y * 0.25
return x1, y1, x2, y2
# 完成上滑操作
def swipeUp(driver):
x1, y1, x2, y2 = getSize(driver)
driver.swipe(x1, y1, x1, y2, 100)
**实现思路2:**获取两个元素的坐标,在掉用swipe方法,从a元素 滚动到 b元素
python
# 获取元素坐标
a_dic = driver.find_element(By.XPATH,'//*[@text="WLAN"]').location # {'x': 144, 'y': 799}
b_dic = driver.find_element(By.XPATH,'//*[@text="通知"]').location # {'x': 144, 'y': 1471}
# 将通知 滚动到 WLAN
driver.swipe(b_dic["x"], b_dic["y"], a_dic["x"], a_dic["y"], duration=100)
方式2: 通过元素的相对位置进行滚动
python
# 页面滚动
el1 = driver.find_element(By.XPATH, '//*[@text="显示"]')
el2 = driver.find_element(By.XPATH, '//*[@text="WLAN"]')
# 将"显示" 滚动到 "WLAN"位置
driver.scroll(el1, el2)
如图所示,将下面的"显示"滑动到上面的"WLAN"位置
3.获取界面的xml源码
方法 : driver.page_source()
用法 :可以用来断言或检查
python
page = driver.page_source()
assert '登陆成功' in page
4.拖拽操作driver.drag_and_drop()
语法:driver.drag_and_drop(el1, el2) --元素1:el1,元素2:el2
作用:将el1元素,拖拽到el2
python
# 拖拽操作
el1 = driver.find_element(By.XPATH, '//*[@text="浏览器"]')
el2 = driver.find_element(By.XPATH, '//*[@text="开发者头条"]')
driver.drag_and_drop(el1, el2)
5、事件链TouchAction
**作用:**构建相对比较复杂的,连续的触摸行为
使用步骤
通过" TouchAction" 类,创建事件链对象,然后传入 driver对象
通过添加各种方法完成事件
- 按下
- 长按
- 移动
- 等待
- 松手
- 轻敲
- ...
代码示例:
python
# 事件链操作TouchAction
# 导包
from appium.webdriver.common.touch_action import TouchAction
# 实例化对象
action = TouchAction(driver)
time.sleep(1)
# 定位元素
ele1 = driver.find_element(By.XPATH, "//*[@text='通知']")
ele2 = driver.find_element(By.XPATH, "//*[@text='WLAN']")
# 拖拽操作,将ele2,拖到 ele1位置
# press:按下操作 .wait(100):按下持续时间 move_to(ele1):移动到目标元素或坐标
action.press(ele1).wait(1000).move_to(ele2)
# 完成后,松手操作 release():松手动作
action.release()
# 提交事件链,生效
action.perform()
# 再次滑动
ele3 = driver.find_element(By.XPATH, "//*[@text='电池']")
action.press(ele3).wait().move_to(ele1)
# 完成后,松手操作 release():松手动作
action.release()
# 提交事件链,生效
action.perform()
# 点击安全
ele4 = driver.find_element(By.XPATH, "//*[@text='安全']")
ele4.click()
time.sleep(0.5)
# 通过事件链,绘制锁屏图案
# 点击屏幕锁定
driver.find_element(By.XPATH, "//*[@text='屏幕锁定']").click()
time.sleep(0.5)
# 点击图案
driver.find_element(By.XPATH, "//*[@text='图案']").click()
time.sleep(2)
# 拖拽绘制图案
action.press(x=182, y=775)\
.wait(100).move_to(x=449, y=1044) \
.wait(100).move_to(x=190, y=1311) \
.wait(100).move_to(x=714, y=1299)
6、截图/截屏
python
driver.get_screenshot_as_file('网络情况.png')
time.sleep(1)
driver.save_screenshot('网络情况2.png')
7、其它操作
重置 app
方法 : driver.reset()
用法 :相当于卸载重装应用,所以本地缓存会失效。
模拟摇晃设备
方法 : driver.shake
退出键盘
方法 : driver.hide_keyboard()
将 app 置于后台运行 x 秒
方法 : driver.background_app(x)
用法 : x 为置于后台的秒数
模拟系统按键
方法 :driver.press_keycode(KEYCODE_BACK)
用法 :根据 AndroidkeyCode 来完成指定操作
键名 | 描述 | 键值 |
---|---|---|
KEYCODE_CALL | 拨号键 | 5 |
KEYCODE_ENDCALL | 挂机键 | 6 |
KEYCODE_HOME | 按键 Home | 3 |
KEYCODE_MENU | 菜单键 | 82 |
KEYCODE_BACK | 返回键 | 4 |
KEYCODE_SEARCH | 搜索键 | 84 |
KEYCODE_CAMERA | 拍照键 | 27 |
KEYCODE_FOCUS | 拍照对焦键 | 80 |
KEYCODE_POWER | 电源键 | 2 |
获取手机的网络信息
- 获取手机的网络信息:网络信息三种模式分别对应数值
飞行模式: 1
无线网络: 2
移动网络: 4
网络情况可以进行组合: 3=1+2,6=2+4
python
print(driver.network_connection)
# - 设置手机网络信息
python
driver.set_network_connection(2)
time.sleep(1)
print(driver.network_connection)
# - 获取当前手机时间
python
print(driver.device_time)
# - 打开通知栏
python
driver.open_notifications()
九、时间等待
待补充
十、APP自动化框架设计思想
参考文档: