python自动化(四)app自动化:4.appium详解
一.appium desktop简介Appium是一个开源的,适用于原生或混合移动应用( hybrid mobile apps )的自动化测试工具,Appium应用WebDriver: JSON wire protocol驱动安卓和iOS移动应用。它是继承自selenium的webdriver,所以它支持selenium的大部分API,且也有一些特殊的使用方式。appium desktop是一款C
一.appium desktop简介
Appium是一个开源的,适用于原生或混合移动应用( hybrid mobile apps )的自动化测试工具,Appium应用WebDriver: JSON wire protocol驱动安卓和iOS移动应用。它是继承自selenium的webdriver,所以它支持selenium的大部分API,且也有一些特殊的使用方式。
appium desktop是一款C/S架构的软件,其内集成了appium service。我们一般主要使用appium desktop来完成元素的定位及启动appium service。
使用appium desktop定位元素
(1)连接真机或者模拟器
连接真机时,需要使用文件传输模式,且在开发者选项中设置USB调试模式
(2)在appium desktop中启动appium server
(3)启动 Inspector Session,创建一个session会话
- Capability的讲解方式:
是一组设置的键值对的集合,其中键对应设置的名称,而值对应设置的值,主要用于通知appium服务器建立需要的session。
Capability的使用方式可以参考官方文档:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md
我们这里讲解几个常用的key_value。
platformName: 设置被测设备的系统,如:Android
platformVersion:被测设备系统的版本
deviceName:被测设备的序列号(使用adb devices查看)
appPackage:被测app的包名
appActivity:被测app需打开的页面的活动名
noReset:启动时是否不重置app,可以跳过登录,首次打开的弹出等(true或者false)
unicodeKeyboard:设置是否允许中文输入。(true或者false)
resetKeyboard:设置是否允许中文输入。(true或者false)
desired_caps:# 在首次运行测试用例时,不关闭app。默认在首次运行测试用例时会先关闭app,再打开
- 设备各种信息的获取方式:
1.获取连接的设备信息:adb devices
如果设备未连接:adb connect 127.0.0.1:21503来手动连接。adb disconnect 127.0.0.1:21503手动断开连接
如果adb devices一直获取不到设备信息,可以将sdk下的adb.exe复制到模拟器目录下替换原来的adb.exe(需关闭所有adb进程)
如果还是adb连接不上设备,可以adb kill-server,然后再连接
2.获取app的包名:
方式一:如已安装对应的app:adb shell pm list packages -3(-3表示只看第三方的app)
方式二:如还未安装对应的app:aapt d badging 安装包的路径
3.获取app的活动名:
方式一:如已安装对应的app:adb shell dumpsys activity | findstr mFocusedActivity(获取正在运行的app的包名和活动名)
方式二:如还未安装对应的app:aapt d badging apk 安装包的路径
4.安装apk软件
adb install apk文件路径
(4)点击start session,创建连接
(5).appium desktop常用功能介绍
我们常用定位元素功能来辅助我们编写脚本
二.Appium常用API
1.生成对应的驱动driver
第一步:导入webdriver
from appium import webdriver
第二步:设置Capability(被测设备及App的相关信息)
# 设置Capability(被测设备及App的相关信息)
desired_caps ={}
desired_caps['platformName'] = 'Android' # 设置被测设备的系统
desired_caps['platformVersion'] = '7.1.2' # 被测设备系统的版本
desired_caps['deviceName'] = '127.0.0.1:21503 device' # 被测设备的序列号
desired_caps['appPackage'] = 'com.jingdong.app.mall' # 被测app的包名
desired_caps['appActivity'] = '.MainFrameActivity' # 被测app需打开的页面的活动名
desired_caps['noReset'] = 'true' # 启动时是否不重置app,可以跳过登录,首次打开的弹出等
desired_caps['unicodeKeyboard'] = 'true' # 设置中文输入
desired_caps['resetKeyboard'] = 'true' # 设置中文输入
desired_caps['desired_caps'] = 'true' # 在首次运行测试用例时,不关闭app。默认在首次运行测试用例时会先关闭app,再打开
第三步:创建一个driver
格式:webdriver.Remote(‘http://appium server的ip:端口号/wd/hub’,Capability信息)
from appium import webdriver
# 设置Capability(被测设备及App的相关信息)
desired_caps ={}
desired_caps['platformName'] = 'Android' # 设置被测设备的系统
desired_caps['platformVersion'] = '7.1.2' # 被测设备系统的版本
desired_caps['deviceName'] = '127.0.0.1:21503 device' # 被测设备的序列号
desired_caps['appPackage'] = 'com.jingdong.app.mall' # 被测app的包名
desired_caps['appActivity'] = '.MainFrameActivity' # 被测app需打开的页面的活动名
desired_caps['noReset'] = 'true' # 启动时是否不重置app,可以跳过登录,首次打开的弹出等
desired_caps['unicodeKeyboard'] = 'true' # 设置中文输入
desired_caps['resetKeyboard'] = 'true' # 设置中文输入
# 生成对应的driver
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
2.app元素定位
Appium中元素定位的方式:
(1)ID定位:(本质是找app页面元素的resource-id属性的值),当页面有多个相同id的元素时,就不能使用id定位了。
方式一:driver.find_element_by_id('com.xueqiu.android:id/home_search')
方式二:driver.find_element(MobileBy.ID,'com.xueqiu.android:id/home_search')
(2)class name 定位(不推荐,一般定位不准确)
driver.find_element_by_class_name('class值')
driver.find_element(MobileBy.CLASS_NAME,'class值')
(3)xpath定位(使用相对xpath,绝对xpath太长会定位失败)
driver.find_element_by_xpath('//*[@resource-id="com.xueqiu.android:id/name" and @text="阿里巴巴"]')
driver.find_element(MobileBy.XPATH,'//*[@resource-id="com.xueqiu.android:id/name" and @text="阿里巴巴"]')
driver.find_element(MobileBy.XPATH,'//*[contains(@text,"次外出")]').click()
Appium中定位元素的方式与selenium十分相似,可以参考selenium的使用。
还包括一些Android和ISO特有的一些定位方式,需要时自己去查看
其他定位工具(uiautomatorviewer)
uiautomatorviewer是sdk自带的一个工具,也可以定位元素。
这个工具在我们的sdk目录的tools目录下,运行该文件即可打开uiautomatorviewer工具。uiautomatorviewer和appiunm的定位工具不能同时打开。
3.app控件的交互
元素的常用方法
appium中元素的常用方法与selenium也十分相似,所以我们可以参考selenium中的方法。
import pytest
from appium import webdriver
from selenium.webdriver.common.by import By
class TestXueQiu:
def setup(self):
# 设置Capability(被测设备及App的相关信息)
desired_caps = {}
desired_caps['platformName'] = 'Android' # 设置被测设备的系统
desired_caps['platformVersion'] = '5.1.1' # 被测设备系统的版本
desired_caps['deviceName'] = '127.0.0.1:21503 device' # 被测设备的序列号
desired_caps['appPackage'] = 'com.xueqiu.android' # 被测app的包名
desired_caps['appActivity'] = '.main.view.MainActivity' # 被测app需打开的页面的活动名
desired_caps['noReset'] = 'true' # 每次打开被测app时,不清除之前的数据
desired_caps['unicodeKeyboard'] = 'true' # 重置键盘,如果需要输入中文需要设置这一项
desired_caps['resetKeyboard'] = 'true' # 允许重置键盘,如果需要输入中文需要设置这一项
# 生成对应的driver
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 设置隐私等待
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.quit()
def test_xueqiu_002(self):
"""
1.打开雪球app
2.定位首页搜索框
3.判断搜索框是否可用
4.打印搜索框的name值
5.点击搜索框输入’alibaba‘
6.判断阿里巴巴是否可见
7.如果可见打印“搜索成功”,否则打印“搜索失败”
:return:
"""
ele_search = self.driver.find_element_by_id('com.xueqiu.android:id/home_search')
ele_search_enable = ele_search.is_enabled()
print('\n搜索框是否可用:',ele_search_enable)
ele_search_name = ele_search.get_attribute('name')
print('搜索框的name:',ele_search_name)
print('搜索框的坐标:',ele_search.location)
print('搜索框的长宽:',ele_search.size)
if ele_search_enable:
ele_search.click()
self.driver.find_element_by_id('com.xueqiu.android:id/search_input_text').send_keys('alibaba')
ele_ali = self.driver.find_element_by_xpath('//*[@resource-id="com.xueqiu.android:id/name" and @text="阿里巴巴"]')
ele_ali_displayed = ele_ali.is_displayed()
# print('阿里巴巴是否可见:',ele_ali_displayed)
if ele_ali_displayed:
print('搜索成功')
else:
print('搜索失败')
4.等待
appium中的等待跟selenium中一样。这里不再讲解
5.触碰操作自动化
我们可以使用TouchAction来完成对手机触碰的操作
TouchAction的使用格式
格式:
action = TouchAction(self.driver) # 实例化一个touchaction对象
action.方法 # 给action添加方法
action.perform() # 执行action
Touchaction的常用方法:
1.按下:
action.press(ele)----------在对应元素的位置按下,参数为某个元素
action.press(x=a,y=b)----------在(a,b)坐标的位置按下,参数为x,y
2.释放:
action.release()-----释放操作
3.移动:
action.move_to(ele)----------移动到对应元素的位置,参数为某个元素
action.move_to(x=a,y=b)----------移动到(a,b)坐标的位置,参数为某个元素
4.长按
action.long_press(ele)-------在对应元素的位置长按,参数为某个元素
action.long_press(x=a,y=b)-------在(a,b)坐标的位置长按,参数为x,y
5.等待
action.wait(200)------等待200毫秒
6.点击
action.tap(ele)----------点击对应元素的位置,参数为某个元素
action.tap(x=a,y=b)----------点击(a,b)坐标的位置,参数为某个元素
实现屏幕滑动
方式一:action.press(ele1).move_to(ele2).release()---------从元素ele1滑动到元素ele2
方式二:action.press(x=70,y=1160).move_to(x=70,y=610).release()-----从(70,1160)滑动到(70,610)
注意,方式二的定位跟手机屏幕大小有关,兼容性不太好,可以进行改进,详见方式3
方式三:
win_size= self.driver.get_window_size() #获取设备屏幕的大小
width = win_size['width'] #屏幕的宽
height = win_size['height'] #屏幕的长
x = int(width/2)
y1 = int(height * 4/5)
y2 = int(height * 1/5)
action = TouchAction(self.driver)
action.press(x=x,y=y1).move_to(x=x,y=y2).release() #实现滑动,而且清楚了屏幕大小对坐标点的影响
action.perform()
6.高级定位技巧
(1)xpath高级运用
举例:
//*[@resource-id="com.xueqiu.android:id/name" and @text="阿里巴巴"]--------定位resource-id="com.xueqiu.android:id/name和text="阿里巴巴"的任何元素
//*[@text='BABA']/../../../..//*[@resource-id='com.xueqiu.android:id/current_price']----定位text='BABA'的任意元素的父节点的父节点的父节点的父节点的子孙节点中resource-id='com.xueqiu.android:id/current_price的任意类型的元素
(2)uiautomator定位
举例:
1.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/login_account")')--使用resourceId定位
2.driver.find_element_by_android_uiautomator('new UiSelector().textContains("帐号密码登录")')---使用text模糊匹配定位
3.driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.xueqiu.android:id/tab_name").text("我的")')----使用resourceId和text组合定位
# uiautomator实现滚动查找页面元素
self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("持有封基").instance(0));').click()
----滚动查找页面text为‘持有封基’的元素
7.特殊控件toast的识别
8.appiunm设备交互api
(1)模拟来电
self.driver.make_gsm_call('13118172284',GsmCallActions.CALL)
# 第一个参数:来电号码
# 第二个参数:行为(GsmCallActions.CALL--表示来电话)
(2)模拟短信
self.driver.send_sms('131-181-72284','hello.sb')
# 第一个参数:号码
# 第二个参数:发送的信息
(3)模拟网络切换
self.driver.set_network_connection(1)
# 参数:需要设置的网络等级
# 0:数据模式关闭,wifi模式关闭,飞行模式关闭
# 1:数据模式关闭,wifi模式关闭,飞行模式开启
# 2:数据模式关闭,wifi模式开启,飞行模式关闭
# 4:数据模式开启,wifi模式关闭,飞行模式关闭
# 6:数据模式开启,wifi模式开启,飞行模式关闭
(3)截屏
self.driver.get_screenshot_as_file('./kkk.png')
9.获取元素属性
格式:element.get_attribute(‘属性名’)
element1.get_attribute('text')--------获取元素element1的text属性的值
常用的属性:
text----文本
resource-id----id属性
class----class属性
content-desc
checkable----是否可检测
checked----是否已检测
enable----是否可操作
fousable----是否可聚焦
focused----是否已聚焦
scrollable----是否可滚动
long-clickable----是否可长按
selected----是否已选择
bounds----坐标值
10.断言
(1)普通断言(常用)
格式:assert 条件
条件为真,用例通过,条件为假,用例失败
(2)hamcrest框架断言
官网:https://github.com/hamcrest/PyHamcrest
使用方法:
安装:pip install PyHamcrest
导入:from hamcrest import *
运用:assert_that(要断言的对象,断言方法,‘失败提醒信息’)-----失败提醒信息参数可以不加
# 常用的断言匹配方法
#对象的断言方法:
assert_that('ass',equal_to('ass'))---匹配相等对象
assert_that('shj',has_length(3))----匹配对象的长度是否满足
assert_that(element1,has_property('text'))---匹配元素element1有text属性
assert_that(element1,has_property('text','我的'))--匹配元素element1有text属性,且属性值为‘我的’
assert_that(6,close_to(8,2))---匹配接近给定的数字值
这里我们只介绍了几种方法,更多的可以自己去官网查看
11.获取页面源码
driver.page_source
三.android web页面测试
1.appium多架构支持
appium支持原生,web,混合等多种架构app的测试。
- 原生app:单纯的app,需要安装apk文件
- web应用:应用在浏览器中,不需要安装apk文件
2.web页面app测试
(1)环境准备
1.获取浏览器驱动。chromedriver
第一步:查看浏览器版本
第一种方式:使用详情查看,这种有可能看不到
第二种方式:使用真机或模拟器中的浏览器,访问https://liulanmi.com/labs/core.html查看
2.下载对应的driver
国内镜像:https://npm.taobao.org/mirrors/chromedriver/
github:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md
3.脚本编写driver配置
caps = {}
caps['platformName'] = 'Android' # 被测设备为Android
caps['platformVersion'] = '5.1.1' # 被测设备系统版本
caps['deviceName'] = '127.0.0.1:21503' # 被测设备
caps['browserName'] = 'Browser' # 设置使用默认浏览器
caps['chromedriverExecutable'] = 'E:/driver/app_driver/chromedriver.exe' # 设置chromedriver的路径
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',caps)
(2)元素定位
webview测试,不像原生app。不能使用appium的inspector和uiautomator来定位元素
方法:在PC的chrome浏览器上,使用:chrome://inspect,来渲染手机端的浏览器。实现定位
这样要求手机端必须能访问到google网址,需要翻墙。可以网上下载离线开发调试工具包
解决办法:https://www.cnblogs.com/slmk/p/7591126.html
定位方法:跟web页面一样
3.混合应用测试
(1)如何判断一个页面是原生页面,还是webview(h5)页面
(2)什么是webview
(3)抓取webview的前提
(4)混合页面
原生页面元素使用app的定位方式,webview页面的元素使用chrome://inspect定位
(5)获取混合app中,定位webview需要的chromedrier的版本
测试混合应用app,出了需要设置apppackage和appactivity外,还需要设置chromedrier路径。
获取chromedrier版本的方法:
第一步:获取app中webview的包名
第二步:通过包名获取版本信息
四.Capability的高级使用
1.newCommandTimeout
newCommandTimeout设置appium等待下一个请求发送的间隔时间,默认是60s
在自动化用例中,存在上传下载大文件时,可以设置newCommandTimeout长一些
caps['newCommandTimeout'] = 300
# 设置appium等待时间为300s
2.udid
udid设置自动化要使用的设备,用于多设备的情况。默认是选择设备列表中的第一个设备
caps['udid'] = 'asiodf'
# 选择设备asiodf
实际上deviceName并不能决定我们选择的设备。udid才可以
3.autoGrantPermissions
autoGrantPermissions用于处理权限授予的弹框,值为false或者true
注意:如果noReset为true,autoGrantPermissions则不生效
4.noReset
noReset表示在建立session时,是否不关闭app,清除app数据,卸载app。值为true或者false
5.fullReset
fullReset与noReset相反,在建立session时,是否关闭app,清除app数据,并且卸载app。值为true或者false
6.dontStopAppOnReset
dontStopAppOnReset:在脚本开始运行时,不关闭app。默认为false,会关闭app
五.appium原理与协议分析
本节重点:理解客户端,appium server,uiautomator2-server的协议
1.appium客户端协议
appium客户端主要使用webdriver和Mobile JSON Wire Protocol协议(底层还是HTTP),支持多语言。
(1)webdriver协议
webdriver协议是w3c协议的一种,定义了操作web端浏览器的各种接口和协议规范。
我们使用appium或者selenium编写脚本,实际上就是使用webdriver协议。来实现自动化用例
(2)Mobile JSON Wire Protocol协议
Mobile JSON Wire Protocol协议是appium开发团队,在webdriver协议之上封装的一套协议,用于解决对移动端的一些操作支持。Mobile JSON Wire Protocol协议也是w3c组织的一员。
appium客户端使用两大协议将自动化的请求发送到appium server,appium server再遵循特定的协议将请求发送给uiautomator服务端,由uiautomator服务端来实际完成各种自动化操作
十.实战
1.企业微信自动打卡
#! /usr/bin/python
# -*- coding: utf-8 -*-
import time
import pytest
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
class TestAutoClock:
def setup(self):
caps = {}
caps['platformName'] = 'Android' # 被测设备为Android
caps['platformVersion'] = '5.1.1' # 被测设备系统版本
caps['deviceName'] = '127.0.0.1:21503' # 被测设备
caps['appActivity'] = '.launch.WwMainActivity' # 被测app要打开的页面
caps['appPackage'] = 'com.tencent.wework' # 被测app的包名
caps['noReset'] = 'true' # 启动时是否不重置app,可以跳过登录等
caps['unicodeKeyboard'] = 'true' # 设置中文输入
caps['resetKeyboard'] = 'true' # 设置中文输入
caps['settings[waitForIdleTimeout]'] = 0
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',caps)
self.driver.implicitly_wait(15)
def teardown(self):
self.driver.quit()
def test_autoclock(self):
"""
企业微信自动打卡
:return:
"""
self.driver.find_element(MobileBy.XPATH,'//*[@text="工作台"]').click()
# self.driver.find_element_by_android_uiautomator('new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("").instance(0));').click()
# 滚动查找
self.driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("打卡").instance(0));').click()
self.driver.find_element(MobileBy.XPATH,'//*[@text="外出打卡"]').click()
# 查找text包含xx的元素
self.driver.find_element(MobileBy.XPATH,'//*[contains(@text,"次外出")]').click()
time.sleep(2)
assert '外出打卡成功' in self.driver.page_source
if __name__ == "__main__":
pytest.main(['-vs','test_wework_autoclock.py'])
更多推荐
所有评论(0)