appium总结,包含入门、进阶、实战
这篇文章面向与实用,拿来即用
基础的事件不进行描述
一、环境搭建
包含Node.js Appium Appium-desktop Appium-doctor Appiun-Python-Client
Python JDK Andriod SDK。配置参考
二、基础操作
Toast元素识别
在app中经常会看到App界面有一些弹窗提示,这些提示元素出现后等待3秒左右就会自动消失,获取不到焦点,无法被点击。
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
代码实现
模拟环境登陆测试,检测到页面出现Toast,进行相关处理。
# 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)
滑动操作
在操作app时会出现滑动操作,如刷抖音、浏览朋友圈进行左右或者上下滑动。
滑动示意图如下:
实践应用
测试场景
安装启动考研帮,手动向水平左滑动首页引导页面。
点击“立即体验”进入登录页面
代码实现
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()
连续滑动操作
实战——九宫格滑动操作
测试场景
安装启动随手记App 启动App后在密码设置选项中开启手机密码并滑动九宫格设置如下图形密码:
代码实现
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()
框架学习unittest
框架功能
我框架的编写方式,从配置文件入手,操作流程在配置文件中按照顺序进行配置,进行业务流程操作,进行数据配置,进行封装主函数,进行并发运行。
Appium并发综合测试实践
并发测试我自己是这么理解,分配相应的端口,检测端口是否被占用,构建appium进程组,
测试场景
并发启动2个appium服务,再并发启动2台设备测试考研帮App
2个appium服务,端口配置如下:
Appium服务器端口:4723,bp端口为4724
Appium服务器端口:4725,bp端口为4726
2台设备:
127.0.0.1:62025
127.0.0.1:62001
测试app:考研帮Andriod版
场景分析
其实就是将前面所讲的两部分组合起来,先启动appium服务,分配端口设备并发启动app。进行业务操作。
代码执行
from appium_sync.multi_appium import appium_start
from appium_sync.multi_devices import appium_desired
from appium_sync.check_port import *
from time import sleep
import multiprocessing
devices_list=['127.0.0.1:62025','127.0.0.1:62001']
def start_appium_action(host,port):
'''检测端口是否被占用,如果没有被占用则启动appium服务'''
if check_port(host,port):
appium_start(host,port)
return True
else:
print('appium %s start failed!' %port)
return False
def start_devices_action(udid,port):
'''先检测appium服务是否启动成功,启动成功则再启动App,否则释放端口'''
host='127.0.0.1'
if start_appium_action(host,port):
appium_desired(udid,port)
else:
release_port(port)
def appium_start_sync():
'''并发启动appium服务'''
print('====appium_start_sync=====')
#构建appium进程组
appium_process=[]
#加载appium进程
for i in range(len(devices_list)):
host='127.0.0.1'
port = 4723 + 2 * i
appium=multiprocessing.Process(target=start_appium_action,args=(host,port))
appium_process.append(appium)
# 启动appium服务
for appium in appium_process:
appium.start()
for appium in appium_process:
appium.join()
sleep(5)
def devices_start_sync():
'''并发启动设备'''
print('===devices_start_sync===')
#定义desired进程组
desired_process = []
#加载desired进程
for i in range(len(devices_list)):
port = 4723 + 2 * i
desired = multiprocessing.Process(target=start_devices_action, args=(devices_list[i], port))
desired_process.append(desired)
#并发启动App
for desired in desired_process:
desired.start()
for desired in desired_process:
desired.join()
if __name__ == '__main__':
appium_start_sync()
devices_start_sync()
并发用例执行
测试场景
在上面的基础上,并发启动设备执行点击操作。
代码实现
from selenium.common.exceptions import NoSuchElementException
class KybTest(object):
def __init__(self,driver):
self.driver=driver
def check_cancelBtn(self):
print('check cancelBtn')
try:
cancelBtn = self.driver.find_element_by_id('android:id/button2')
except NoSuchElementException:
print('no cancelBtn')
else:
cancelBtn.click()
def check_skipBtn(self):
print('check skipBtn')
try:
skipBtn = self.driver.find_element_by_id('com.tal.kaoyan:id/tv_skip')
except NoSuchElementException:
print('no skipBtn')
else:
skipBtn.click()
def skip_update_guide(self):
self.check_cancelBtn()
self.check_skipBtn()
将执行的用例集成到 multi_devices.py
from appium import webdriver
import yaml
from time import ctime
from appium_sync.kyb_test import KybTest
# 读取yaml文件配置
with open('desired_caps.yaml','r') as file:
data=yaml.load(file)
devices_list=['127.0.0.1:62001','127.0.0.1:62025']
def appium_desired(udid,port):
desired_caps={}
desired_caps['platformName']=data['platformName']
desired_caps['platformVersion']=data['platformVersion']
desired_caps['deviceName']=data['deviceName']
desired_caps['udid']=udid
desired_caps['app']=data['app']
desired_caps['appPackage']=data['appPackage']
desired_caps['appActivity']=data['appActivity']
desired_caps['noReset']=data['noReset']
print('appium port:%s start run %s at %s' %(port,udid,ctime()))
driver=webdriver.Remote('http://'+str(data['ip'])+':'+str(port)+'/wd/hub',desired_caps)
driver.implicitly_wait(5)
k=KybTest(driver)
k.skip_update_guide()
return driver
if __name__ == '__main__':
appium_desired(devices_list[0],4723)
appium_desired(devices_list[1],4725)