appium学习(二)(appium脚本)
第一个appium脚本
测试环境
- Win 10 64bit
- Python 3.5
- Appium 1.7.2
- Andriod 5.1.1 模拟器& Android 5.1 MX4
- 测试App:考研帮Android版 3.1.0
测试场景
自动安装考研帮App(kaoyan3.1.0.apk),然后启动App
测试步骤
- 获取待测试app的packageName和Activity
- 配置Capability
- 连接设备
- 编辑脚本并运行
- 查看结果
运行前检查事项
- 检查设备是否连接
- 检查Appium server是否启动
- 检查Capability配置信息是否正确
测试脚本
test_kyb.py
from appium import webdriver
desired_caps={}
desired_caps['platformName']='Android'
#模拟器设备
desired_caps['platformVersion']='5.1.1'
desired_caps['deviceName']='127.0.0.1:62025'
#mx4真机
# desired_caps['platformVersion']='5.1'
# desired_caps['deviceName']='MX4'
# desired_caps['udid']='750BBKL22GDN'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk'
desired_caps['appPackage']='com.tal.kaoyan'
desired_caps['appActivity']='com.tal.kaoyan.ui.activity.SplashActivity'
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
pycharm常用快捷键
- 复制粘贴当前行 Ctrl+D
- 注释 Ctrl+/
- 运行当前脚本 Ctrl+shift+F10
- 折叠展开代码 Ctrl + Numpad + /-
- 方法定义跳转 Ctrl+B
1.首次启动Appium会在设备上安装2个守护app,Appium Settings和Unlock 部分设备系统由于权限的问题(如:三星S6 edge+)需要用户手动确认安装,否则不安装守护App会导致脚本运行失败,安装好后不要随意卸载这两个App。
- Unlock :用于解锁手机弹窗提示
- Appium Setting:Appium守护app
- from appium import webdriver 中的webdriber模块和selenium中的webdriver模块不一样!
webdriver模块源码路径:
{python安装路径}}\Lib\site-packages\appium\webdriver
Appium报错&解决方案——那些年我们踩过的坑
Appium服务未启动
urllib.error.URLError: <urlopen error [WinError 10061] 由于目标计算机积极拒绝,无法连接。
【解决方案】点击启动Appium按钮后,出现[Appium] Welcome to Appium v1.7.2提示后再运行脚本
会话冲突
error: Failed to start an Appium session, err was: Error: Requested a new session but one was in progress
【报错分析】 之前的会话没有关闭,然后你又运行了测试实例,也没有设置覆盖.
【解决方案】 重新停止appium服务,开启Appium服务 在AdVance界面勾选Allow Session Override选项 ,重启Appium 测试结束在AfterClass加driver.quit()
未安装java环境
selenium.common.exceptions.WebDriverException: Message: A new session could not be created. (Original error: 'java -version' failed. Error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c "java -version"
设备未连接
selenium.common.exceptions.WebDriverException: Message: An unknown server-side error occurred while processing the command. Original error: Could not find a connected Android device.
【解决方案】由于设备未连接,或者连接后未开启USB Debug。需要重新连接设备即可
更换手机设备后如下对应的属性要记得更新,否则无法正常运行脚本
desired_caps['platformVersion'] = 'XXX' desired_caps['deviceName'] = 'Galaxy S6 edge+'
launchable activity 值写错
Activity used to start app doesn't exist or cannot be launched! Make sure it exists and is a launchable activity
【解决方案】
- launchable activity 写错更正即可。
- 如果是存在此activity,则一定是AndroidMainfest.xml.xml中,当前activity设置的属性exported=false,表示当前activity无法被外部程序唤醒。(appium无法唤醒此类)需要研发人员去修改参数。
系统权限问题
Failure [INSTALL_FAILED_USER_RESTRICTED])
【解决方案】
- USB安装管理权限限制,关闭即可。
- 开启安装允许未知来源app选项
服务异常
An unknown server-side error occurred while processing the command” while opening the App
【解决方案】重新启动Appium服务
元素定位
与Web自动化测试一样,app自动化测试过程中最重要一个环节就是元素定位,只有准确定位到了元素才能进行相关元素的操作,如输入、点击、拖拽、滑动等。appium提供了许多元素定位的方法,如id定位、name定位、class定位、层级定位等等.... 接下来将会给大家来实践运用这些定位技巧。
元素定位方式
- id
- name
- class
- List定位
- 相对定位
- Xpath定位
- H5页面元素定位
- Uiautomator定位
id定位
日常生活中身边可能存在相同名字的人,但是每个人的身份证号码是唯一的,在app界面元素中也可以使用id值来区分不同的元素,然后进行定位操作。Appium中可以使用 find_element_by_id() 方法来进行id定位。
测试场景1
- 安装考研帮kaoyan3.1.0.apk
- 点击升级页面取消按钮
- 点击引导页面的跳过按钮
kyb_cancel_skip.py
from appium import webdriver
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['deviceName']='127.0.0.1:62025'
desired_caps['platforVersion']='5.1.1'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk'
desired_caps['appPackage']='com.tal.kaoyan'
desired_caps['appActivity']='com.tal.kaoyan.ui.activity.SplashActivity'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(5)
driver.find_element_by_id('android:id/button2').click()
driver.find_element_by_id('com.tal.kaoyan:id/tv_skip').click()
思考
- 如果安装的版本最新的包,或者升级到了最新的版本,则启动后没有升级弹窗元素该如何处理?
- 跳过引导页面首次启动和非首次启动场景该如何处理?
方案探索1——if条件判断
有同学可能想到用if来做条件判断,判断元素是否存在,存在则点击,不存在则跳过。
kyb_cancel_skip_if.py
from appium import webdriver
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['deviceName']='127.0.0.1:62025'
desired_caps['platforVersion']='5.1.1'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk'
desired_caps['appPackage']='com.tal.kaoyan'
desired_caps['appActivity']='com.tal.kaoyan.ui.activity.SplashActivity'
desired_caps['noReset']='True'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(5)
cancelBtn=driver.find_element_by_id('android:id/button2')
skipBtn=driver.find_element_by_id('com.tal.kaoyan:id/tv_skip')
if cancelBtn:
cancelBtn.click()
else:
print('no cancelBtn')
if skipBtn:
skipBtn.click()
else:
print('no skipBtn')
方案探索2——异常捕捉
kyb_cancel_skip_try.py
既然上面的if语句判断无法生效,但是我们发现一个突破口,那就是捕捉NoSuchElementException异常
from appium import webdriver
from selenium.common.exceptions import NoSuchElementException
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['deviceName']='127.0.0.1:62025'
desired_caps['platforVersion']='5.1.1'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\kaoyan3.1.0.apk'
desired_caps['appPackage']='com.tal.kaoyan'
desired_caps['appActivity']='com.tal.kaoyan.ui.activity.SplashActivity'
desired_caps['noReset']='True'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(5)
def check_cancelBtn():
print("check_cancelBtn")
try:
cancelBtn = driver.find_element_by_id('android:id/button2')
except NoSuchElementException:
print('no CancelBtn')
else:
cancelBtn.click()
def check_skipBtn():
print("check_skipBtn")
try:
skipBtn = driver.find_element_by_id('com.tal.kaoyan:id/tv_skip')
exceptNoSuchElementException:
print('no skipBtn')
else:
skipBtn.click()
check_updateBtn()
check_skipBtn()
id定位综合实践——自动登录
测试场景
- 启动App,进入到登录界面
- 在登录页面输入用户名“自学网2018”,密码‘zxw2018’ 然后点击登录。
- 可以把启动后检测升级弹窗和引导页面的模块抽离作为独立的模块被其他模块调用,提高代码复用率。
- 获取用户名密码输入框和登录按钮的元素id属性,另外要考虑启动时App之前是否登录过账号,已经登录过和未登录场景流程不一样。
需求分析
注意:send_keys()传入中文时需要在capability中配置如下内容
desired_caps['unicodeKeyboard']="True" desired_caps['resetKeyboard']="True"
设置之后会有Appium的输入法守护来执行输入操作
代码实现
kby_login.py
from find_element.capability import driver,NoSuchElementException
def login():
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').clear()
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').send_keys('自学网2018')
driver.find_element_by_id('com.tal.kaoyan:id/login_password_edittext').send_keys('zxw2018')
driver.find_element_by_id('com.tal.kaoyan:id/login_login_btn').click()
try:
driver.find_element_by_id('com.tal.kaoyan:id/mainactivity_button_mysefl')
except NoSuchElementException:
login()
else:
driver.find_element_by_id('com.tal.kaoyan:id/mainactivity_button_mysefl').click()
driver.find_element_by_id('com.tal.kaoyan:id/activity_usercenter_username').click()
login()
注意:
使用Appium做了输入操作之后,如果出现输入法无法唤起,可以在系统设置——语言和输入法——将当前输入法替换为系统输入法或者其他输入法。
name定位
根据name进行定位,对于android来说,就是text属性
用法
from find_element.capability import *
driver.find_element_by_name('请输入用户名').send_keys('2017')
driver.find_element_by_name('登录').click()
说明:由于text稳定性不是很好,所以appium 1.5开始废弃了该方法。
classname定位
classname定位是根据元素类型来进行定位,但是实际情况中很多元素的classname都是相同的,
如上例中登录页面中的用户名和密码都是clasName属性值都是:“android.widget.EditText” 因此只能定位第一个元素也就是用户名,而密码输入框就需要使用其他方式来定位,这样其实很鸡肋.一般情况下如果有id就不必使用classname定位。
by_classname.py
from find_element.capability import driver
driver.find_element_by_class_name('android.widget.EditText').send_keys('自学网2018')
driver.find_element_by_class_name('android.widget.EditText').send_keys('zxw2018')
driver.find_element_by_class_name('android.widget.Button').click()
相对定位
相对定位是先找到该元素的有对应属性的父元素节点,然后基于父元素进行元素定位。
测试案例
不使用id元素定位方式,在新用户注册界面点击添加头像按钮。
代码实现
by_relative.py
from find_element.capability import driver
driver.find_element_by_id('com.tal.kaoyan:id/login_register_text').click()
root_element=driver.find_element_by_id('com.tal.kaoyan:id/activity_register_parentlayout')
root_element.find_element_by_class_name('android.widget.ImageView').click()
xpath定位
xpath定位是一种路径定位方式,主要是依赖于元素绝对路径或者相关属性来定位,但是绝对路径xpath执行效率比较低(特别是元素路径比较深的时候),一般使用比较少。通常使用xpath相对路径和属性定位。
xpath路径表达式
|
表达式 |
描述 |
|
/ |
从根节点选取。 |
|
// |
从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
|
nodename |
选取此节点的所有子节点。 |
|
. |
选取当前节点。 |
|
.. |
选取当前节点的父节点。 |
|
@ |
选取属性。 |
|
通配符 |
描述 |
|
* |
匹配任何元素节点。 |
|
@* |
匹配任何属性节点。 |
|
node() |
匹配任何类型的节点。 |
实践案例
使用xpath定位元素来进行登录操作。
by_xpath.py
from find_element.capability import driver
driver.find_element_by_xpath('//android.widget.EditText[@text="请输入用户名"]').send_keys('zxw1234')
driver.find_element_by_xpath('//*[@class="android.widget.EditText" and @index="3"]').send_keys('zxw123456')
driver.find_element_by_xpath('//android.widget.Button').click()
# driver.find_element_by_xpath('//*[@class="android.widget.Button"]').click()
扩展资料:xpath语法
List定位
前面我们提到相同的classname属性值元素无法区分定位,那么在本节课将使用List定位来解决这个问题。List定位首先是使用find_elements_by_XX获取一组相同的class属性的元素,然后使用数组下标来区分标记不同元素进行相关操作。
测试案例1
在新用户注册界面点击添加头像按钮后,选择指定的图片保存作为头像。
from find_element.capability import driver
driver.find_element_by_id('com.tal.kaoyan:id/login_register_text').click()
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_userheader').click()
images=driver.find_elements_by_id('com.tal.kaoyan:id/item_image')
images[10].click()
driver.find_element_by_id('com.tal.kaoyan:id/save').click()
list定位综合案例——用户注册
测试场景
- 进入注册界面设置头像
- 输入注册信息:用户名、密码、邮箱
- 完善院校和专业信息 (院校:上海-同济大学 专业:经济学类-统计学-经济统计学)
- 完成注册
代码实现
kyb_register.py
from find_element.capability import driver
import random
#进入注册界面选择并设置头像
driver.find_element_by_id('com.tal.kaoyan:id/login_register_text').click()
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_userheader').click()
images=driver.find_elements_by_id('com.tal.kaoyan:id/item_image')
images[10].click()
driver.find_element_by_id('com.tal.kaoyan:id/save').click()
#注册信息填写
username='zxw2018'+'FLY'+str(random.randint(1000,9000))
print('username: %s' %username)
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_username_edittext').send_keys(username)
password='zxw'+str(random.randint(1000,9000))
print('password: %s' %password)
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_password_edittext').send_keys(password)
email='51zxw'+str(random.randint(1000,9000))+'@163.com'
print('email: %s' %email)
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_email_edittext').send_keys(email)
driver.find_element_by_id('com.tal.kaoyan:id/activity_register_register_btn').click()
#院校选择
driver.find_element_by_id('com.tal.kaoyan:id/perfectinfomation_edit_school_name').click()
#选择省份
driver.find_elements_by_id('com.tal.kaoyan:id/more_forum_title')[1].click()
#选择具体院校--同济大学
driver.find_elements_by_id('com.tal.kaoyan:id/university_search_item_name')[1].click()
#专业选择
driver.find_element_by_id('com.tal.kaoyan:id/activity_perfectinfomation_major').click()
#选择经济学类-统计学-经济统计学
driver.find_elements_by_id('com.tal.kaoyan:id/major_subject_title')[1].click()
driver.find_elements_by_id('com.tal.kaoyan:id/major_group_title')[2].click()
driver.find_elements_by_id('com.tal.kaoyan:id/major_search_item_name')[1].click()
#点击“进入考研帮”按钮
driver.find_element_by_id('com.tal.kaoyan:id/activity_perfectinfomation_goBtn').click()
注意:运行前记得将noRest设置为:desired_caps['noReset']='False' 以免之前的注册残留信息干扰。
报错&解决方案
元素定位报错
selenium.common.exceptions.NoSuchElementException: Message: An element could not be located on the page using the given search parameters.
【解决方案】检查元素id值是否写错
UIAutomator定位简介
UIAutomator元素定位是 Android 系统原生支持的定位方式,虽然与 xpath 类似,但比它更加好用,且支持元素全部属性定位.定位原理是通过android 自带的android uiautomator的类库去查找元素。 Appium元素定位方法其实也是基于Uiautomator来进行封装的。
使用方法 find_element_by_android_uiautomator() 可以运用UiAutomator元素定位。
定位方法
- id定位
- text定位
- class name定位
id定位
id定位是根据元素的resource-id属性来进行定位,使用 UiSelector().resourceId()方法即可。
by_Uiautomator.py
from find_element.capability import driver
driver.find_element_by_android_uiautomator\
('new UiSelector().resourceId("com.tal.kaoyan:id/login_email_edittext")').send_keys('zxw1234')
driver.find_element_by_android_uiautomator\
('new UiSelector().resourceId("com.tal.kaoyan:id/login_password_edittext")').send_keys('zxw123456')
driver.find_element_by_android_uiautomator\
('new UiSelector().resourceId("com.tal.kaoyan:id/login_login_btn")').click()
text定位
text定位就是根据元素的text属性值来进行定位,new UiSelector()
driver.find_element_by_android_uiautomator\
('new UiSelector().text("请输入用户名")').send_keys('zxw1234')
class name定位
与Appium class定位方式一样,也是根据元素的class属性来进行定位。
driver.find_element_by_android_uiautomator\
('new UiSelector().className("android.widget.EditText")').send_keys('zxw1234')
元素等待
元素等待作用
设置元素等待可以更加灵活的制定等待定位元素的时间,从而增强脚本的健壮性,提高执
from time import sleep #强制等待5秒 sleep(5)
隐式等待
隐式等待是针对全部元素设置的等待时间
driver.implicitly_wait(20)
显式等待
显式等待是针对某个元素来设置的等待时间。
方法WebDriverWait格式参数如下: from selenium.webdriver.support.ui import WebDriverWait WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) driver : WebDriver timeout : 最长超时时间,默认以秒为单位 poll_frequency : 休眠时间的间隔时间,默认为0.5秒 ignored_exceptions : 超时后的异常信息,默认情况下抛NoSuchElementException异常。
WebDriverWait()一般和until()或until_not()方法配合使用,另外,lambda提供了一个运行时动态创建函数的方法。
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver,10).until(lambda x:x.find_element_by_id("elementID"))
实战案例
测试场景
考研帮登录之后显示等待【论坛】按钮,然后点击。
代码实现
element_wait.py
from find_element.kyb_login import driver
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(driver,3).until(lambda x:x.find_element_by_id('com.tal.kaoyan:id/mainactivity_button_forum'))
driver.find_element_by_id('com.tal.kaoyan:id/mainactivity_button_forum').click()
在日常使用App过程中,经常会看到App界面有一些弹窗提示(如下图所示)这些提示元素出现后等待3秒左右就会自动消失,那么我们该如何获取这些元素文字内容呢

Toast简介
Android中的Toast是一种简易的消息提示框。 当视图显示给用户,在应用程序中显示为浮动。和Dialog不一样的是,它永远不会获得焦点,无法被点击。
Toast类的思想就是尽可能不引人注意,同时还向用户显示信息,希望他们看到。而且Toast显示的时间有限,一般3秒左右就消失了。因此使用传统的元素定位工具,我们是无法定位到Toast元素的(传说中低调奢华有内涵)。
Appium Toast内容获取
Add ability to verify TOAST messages (these can't be interacted with, only text retrieval allowed)
Appium 1.6.3开始支持识别Toast内容,主要是基于UiAutomator2,因此需要在Capablity配置如下参数:
desired_caps['automationName']='uiautomator2'
安装appium-uiautomator2-driver: 安装命令如下:
cnpm install appium-uiautomator2-driver
安装成功后可以在 C:\Users\XXXX\node_modules看到对应的文件:
- _appium-uiautomator2-driver@1.12.0@appium-uiautomator2-driver
- _appium-uiautomator2-server@1.10.0@appium-uiautomator2-server
安装selenium模块
pip install selenium
安装完成后使用如下命令检测是否安装成功
#查看selenium版本 C:\Users\Shuqing>pip show selenium Name: selenium Version: 3.11.0 Summary: Python bindings for Selenium Home-page: https://github.com/SeleniumHQ/selenium/ Author: UNKNOWN Author-email: UNKNOWN License: Apache 2.0 Location: c:\python35\lib\site-packages Requires: Required-by: Appium-Python-Client
测试环境
- jdk版本:"1.8.0_05"
- appium版本:1.7.2 (不能低于1.6.3)
- selenium:3.11.0
- 测试设备:Android 5.1.1
- Python:3.5
- 测试App:考研帮Android app V3.1.0
测试场景
进入登录界面输入错误的用户名或者密码,获取Toast内容:
- “用户名或密码错误,你还可以尝试4次”
- “验证失败次数过多,请15分钟后再试”
代码实现
get_toast.py
# coding=utf-8
from find_element.capability import driver
from selenium.webdriver.support.ui import WebDriverWait
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').clear()
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').send_keys('zxss018')
driver.find_element_by_id('com.tal.kaoyan:id/login_password_edittext').send_keys('zxw2018')
driver.find_element_by_id('com.tal.kaoyan:id/login_login_btn').click()
error_message="用户名或密码错误,你还可以尝试4次"
limit_message="验证失败次数过多,请15分钟后再试"
message='//*[@text=\'{}\']'.format(error_message)
# message='//*[@text=\'{}\']'.format(limit_message)
toast_element=WebDriverWait(driver,5).until(lambda x:x.find_element_by_xpath(message))
print(toast_element.text)
注意:Toast内容为中文时,顶部必须注释# coding=utf-8 否则会因为编解码导致文字识别失败。
应用背景
在实际自动化项目运行过程中,很多时候App可以会出现各种异常,为了更好的定位问题,除了捕捉日志我们还需要对运行时的设备状态来进行截屏。从而达到一种“有图有真相”的效果。
截图方法
方法1
save_screenshot() 该方法直接保存当前屏幕截图到当前脚本所在文件位置。
driver.save_screenshot('login.png')
方法2
get_screenshot_as_file(self, filename)
将截图保留到指定文件路径
driver.get_screenshot_as_file('./images/login.png')
实践案例
测试场景
在考研帮App登录页面输入用户名和密码之后截图,分别保存到当前文件和指定的文件路径。
from find_element.capability import driver
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').clear()
driver.find_element_by_id('com.tal.kaoyan:id/login_email_edittext').send_keys('55555')
driver.find_element_by_id('com.tal.kaoyan:id/login_password_edittext').send_keys('zxw2018')
driver.save_screenshot('login.png')
driver.get_screenshot_as_file('./images/login.png')
driver.find_element_by_id('com.tal.kaoyan:id/login_login_btn').click()
在app应用日常使用过程中,会经常用到在屏幕滑动操作。如刷朋友圈上下滑操作、浏览图片左右滑动操作等。在自动化脚本该如何实现这些操作呢?
在Appium中模拟用户滑动操作需要使用swipe方法,该方法定义如下:
def swipe(self, start_x, start_y, end_x, end_y, duration=None):
"""Swipe from one point to another point, for an optional duration.
:Args:
- start_x - x-coordinate at which to start
- start_y - y-coordinate at which to start
- end_x - x-coordinate at which to stop
- end_y - y-coordinate at which to stop
- duration - (optional) time to take the swipe, in ms.
:Usage:
driver.swipe(100, 100, 100, 400)
滑动解析
滑动主要分为:
- 水平滑动
- 垂直滑动
- 任意方向滑动
滑动轨迹图如下:

测试场景
- 安装启动考研帮,手动向水平左滑动首页引导页面。
- 点击“立即体验”进入登录页面。
代码实现
from time import sleep
from find_element.capability import driver
#获取屏幕尺寸
def get_size():
x=driver.get_window_size()['width']
y=driver.get_window_size()['height']
return x,y
#显示屏幕尺寸(width,height)
l=get_size()
print(l)
#向左滑动
def swipeLeft():
l=get_size()
x1=int(l[0]*0.9)
y1=int(l[1]*0.5)
x2=int(l[0]*0.1)
driver.swipe(x1,y1,x2,y1,1000)
#向左滑动2次
for i in range(2):
swipeLeft()
sleep(0.5)
driver.find_element_by_id('com.tal.kaoyan:id/activity_splash_guidfinish').click()
注意:运行前记得将capablity里面的check_skipBtn()先注释掉,否则直接跳过了无法滑动引导页面
课后作业
把垂直上下滑动以及向右滑动的也封装并实践。
- def swipeUp()
- def swipeDown()
- def swipeRight()
参考答案
def swipeUp():
l = get_size()
x1 = int(l[0] * 0.5)
y1 = int(l[1] * 0.95)
y2 = int(l[1] * 0.35)
driver.swipe(x1, y1, x1, y2, 1000)
def swipeDown():
l=get_size()
x1 = int(l[0] * 0.5)
y1 = int(l[1] * 0.35)
y2 = int(l[1] * 0.85)
driver.swipe(x1, y1, x1, y2, 1000)
def swipeRight():
l=get_size()
y1 = int(l[1] * 0.5)
x1 = int(l[0] * 0.25)
x2 = int(l[0] * 0.95)
driver.swipe(x1, y1, x2, y1, 1000)
滑动操作一般是两点之间的滑动,而实际使用过程中用户可能要进行一些多点连续滑动操作。如九宫格滑动操作,连续拖动图片移动等场景。那么在Appium中该如何模拟这类操作呢?
TouchAction
Touch Action包含一些列操作,比如按压、长按、点击、移动、暂停。由着些不同操作可以组成一套动作。使用TochAction需要先导入对应的模块
from appium.webdriver.common.touch_action import TouchAction
按压
方法:press() 开始按压一个元素或坐标点(x,y)。通过手指按压手机屏幕的某个位置。 press也可以接收屏幕的坐标(x,y)。
press(self, el=None, x=None, y=None) TouchAction(driver).press(x=0,y=308)
长按
方法:longPress() 开始按压一个元素或坐标点(x,y)。 相比press()方法,longPress()多了一个入参,既然长按,得有按的时间吧。duration以毫秒为单位。1000表示按一秒钟。其用法与press()方法相同。
long_press(self, el=None, x=None, y=None, duration=1000)
点击
方法:tap() 对一个元素或控件执行点击操作。用法参考press()。
tap(self, element=None, x=None, y=None, count=1)
移动
方法:move_to() 将指针从上一个点移动到指定的元素或点。
move_to(self, el=None, x=None, y=None)
注意:
移动到目位置有时是算绝对坐标点,有时是基于前面一个坐标点的偏移量,这个要结合具体App来实践。
暂停
方法:Wait()
wait(self, ms=0)
暂停脚本的执行,单位为毫秒。
释放
方法release() 结束的行动取消屏幕上的指针。
release(self)
执行
perform() 执行的操作发送到服务器的命令操作。
perform(self)
TouchAction实战——九宫格滑动操作
九宫格是一种比较常见的图案加密方式,目前很多App都支持设置图案锁,Android原生系统也支持设九宫格图案锁屏。那么我们该如何使用Appium进行滑动操作呢?
测试场景
安装启动随手记App 启动App后在密码设置选项中开启手机密码并滑动九宫格设置如下图形密码:

测试环境
- 夜神模拟器 Android 5.1.1
- 随手记Android版 V10.5.6.0
- Win 10 64bit
- Appium 1.7.2
代码实现
from appium import webdriver
from time import sleep
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['platformVersion']='5.1.1'
desired_caps['deviceName']='127.0.0.1:62025'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\mymoney.apk'
desired_caps['appPackage']='com.mymoney'
desired_caps['appActivity']='com.mymoney.biz.splash.SplashScreenActivity'
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
driver.implicitly_wait(5)
def get_size():
x=driver.get_window_size()['width']
y=driver.get_window_size()['height']
return x,y
def swipeLeft():
l=get_size()
x1=int(l[0]*0.9)
y1=int(l[1]*0.5)
x2=int(l[0]*0.1)
driver.swipe(x1,y1,x2,y1,1000)
def swipeUp():
l = get_size()
x1 = int(l[0] * 0.5)
y1 = int(l[1] * 0.95)
y2 = int(l[1] * 0.35)
driver.swipe(x1, y1, x1, y2, 1000)
#等待启动页面元素,然后向左滑动两次,跳过引导页面
WebDriverWait(driver,6).until(lambda x:x.find_element_by_id("com.mymoney:id/next_btn"))
for i in range(2):
swipeLeft()
sleep(1)
#点击“开始随手记”按钮
driver.find_element_by_id('com.mymoney:id/begin_btn').click()
#检测是否有活动页面弹窗,如果有就点击关闭
try:
closBtn=driver.find_element_by_id('com.mymoney:id/close_iv')
except NoSuchElementException:
pass
else:
closBtn.click()
#点击更多菜单
driver.find_element_by_id('com.mymoney:id/nav_setting_btn').click()
#等待界面菜单加载出来,然后向上滑动
WebDriverWait(driver,6).until(lambda x:x.find_element_by_id("com.mymoney:id/content_container_ly"))
swipeUp()
#点击高级菜单
driver.find_element_by_android_uiautomator('new UiSelector().text("高级")').click()
#点击密码与手势密码菜单
driver.find_element_by_id('com.mymoney:id/password_protected_briv').click()
#点击手势密码保护
driver.find_element_by_id('com.mymoney:id/lock_pattern_or_not_sriv').click()
#连续滑动两次设置图案密码
for i in range(2):
TouchAction(driver).press(x=243,y=381).wait(2000)\
.move_to(x=455,y=390).wait(1000)\
.move_to(x=643,y=584).wait(1000)\
.move_to(x=647,y=784).wait(1000)\
.release().perform()
多点触控操作-----地图缩放
MultiAction
MultiAction 是多点触控的类,可以模拟用户多点操作。主要包含 add() 和 perform() 两个方法, MultiAction可以结合前面所学的 ActionTouch可以模拟出用户的多个手指滑动的操作效果;
from appium.webdriver.common.multi_action import MultiAction from appium.webdriver.common.touch_action import TouchAction
加载:
方法add(self, *touch_actions)将TouchAction对象添加到MultiAction中,稍后再执行。
参数:
- touch_actions - 一个或多个TouchAction对象,描述一个手指要执行的动作链
用法
a1 = TouchAction(driver) a1.press(el1).move_to(el2).release() a2 = TouchAction(driver) a2.press(el2).move_to(el1).release() MultiAction(driver).add(a1, a2)
perform(self) 执行存储在对象中的操作。
用法 a1 = TouchAction(driver) a1.press(el1).move_to(el2).release() a2 = TouchAction(driver) a2.press(el2).move_to(el1).release() MultiAction(driver).add(a1, a2).perform()
多点触控操作实践——地图App缩放
测试场景
安装启动百度地图Android app 进入地图后分别进行放大缩小操作
测试环境
- Appium 1.7.2
- Win10 64bit
- 夜神模拟器 Android5.1.1
- 百度地图Android版 V10.6.5
滑动原理图解

代码实现
multi_action.py
from appium import webdriver
from time import sleep
from appium.webdriver.common.touch_action import TouchAction
from appium.webdriver.common.multi_action import MultiAction
desired_caps={}
desired_caps['platformName']='Android'
desired_caps['deviceName']='127.0.0.1:62025'
desired_caps['platforVersion']='5.1.1'
desired_caps['app']=r'C:\Users\Shuqing\Desktop\com.baidu.BaiduMap.apk'
desired_caps['appPackage']='com.baidu.BaiduMap'
desired_caps['appActivity']='com.baidu.baidumaps.WelcomeScreen'
driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_caps)
driver.implicitly_wait(5)
driver.find_element_by_id('com.baidu.BaiduMap:id/dj2').click()
driver.find_element_by_id('com.baidu.BaiduMap:id/byo').click()
x=driver.get_window_size()['width']
y=driver.get_window_size()['height']
def pinch():
action1=TouchAction(driver)
action2=TouchAction(driver)
zoom_action=MultiAction(driver)
action1.press(x=x*0.2,y=y*0.2).wait(1000).move_to(x=x*0.4,y=y*0.4).wait(1000).release()
action2.press(x=x*0.8,y=y*0.8).wait(1000).move_to(x=x*0.6,y=y*0.6).wait(1000).release()
print('start pinch...')
zoom_action.add(action1,action2)
zoom_action.perform()
def zoom():
action1=TouchAction(driver)
action2=TouchAction(driver)
zoom_action=MultiAction(driver)
action1.press(x=x*0.4,y=y*0.4).wait(1000).move_to(x=x*0.2,y=y*0.2).wait(1000).release()
action2.press(x=x*0.6,y=y*0.6).wait(1000).move_to(x=x*0.8,y=y*0.8).wait(1000).release()
print('start zoom...')
zoom_action.add(action1,action2)
zoom_action.perform()
if __name__ == '__main__':
for i in range(3):
pinch()
for i in range(3):
zoom()

浙公网安备 33010602011771号