前不久部门老大给了一个同时运行多台手机设备的任务,运行脚本时不用手动启appium服务代码自动启。现记录下来实现过程及结果。
1、安装pyyaml及tomorrow
pip install pyyaml (我这已安装过)
pip install tomorrow (我这已安装过)
2、安装命令行版appium
2.1安装命令
npm --registry https://registry.npm.taobao.org install -g appium
2.2验证安装是否成功
cmd里输入appium
3、编写设备配置文件,创建devices.yaml文件
- desc: 设备_vivo,端口_4723
port: 4723
des:
platformName: Android
deviceName: 496ba836
udid: 496ba836
platformVersion: !!str 8.1.0
appPackage: com.tckk.kk
appActivity: com.tckk.kk.ui.start.SplashActivity
noReset: !!bool True #强制转换数据类型
unicodeKeyboard: !!bool True
resetKeyboard: !!bool True
- desc: 设备_leidian,端口_4725
port: 4725
des:
platformName: Android
deviceName: emulator-5554
udid: emulator-5554
platformVersion: !!str 5.1.1
appPackage: com.tckk.kk
appActivity: com.tckk.kk.ui.start.SplashActivity
noReset: !!bool True
unicodeKeyboard: !!bool True
resetKeyboard: !!bool True
4、编写启动服务py文件,创建start_appium.py文件
import os,time
import subprocess
def StartAppium(host="127.0.0.1",port=4723):
"""
启动appium服务
:param host: 访问地址
:param port: 端口号
:return:
"""
a = os.popen('netstat -ano | findstr "%s" '% port)
time.sleep(2)
t1 = a.read()
if "LISTENING" in t1:
print("appium服务已经启动:%s" % t1)
else:
# 启动appium服务,指定bp端口号
bootstrap_port = str(port + 1)
# 把在cmd弹窗输入的命令,直接写到这里
cmd = 'start /b appium -a %s -p %s -bp %s' % (host, port, bootstrap_port)
# 去掉 “/b”,即可以打开cmd弹窗运行
# cmd = 'start /b appium -a %s -p %s -bp %s' % (host, port, bootstrap_port)
# 打印输入的cmd命令,及时间
print("%s at %s " % (cmd, time.ctime()))
subprocess.Popen(cmd, shell=True, stdout=open('./report' + str(port) + '.log', 'a'),
stderr=subprocess.STDOUT)
5、封装元素定位方法,创建find_element.py文件
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class AppPage():
def __init__(self,driver):
self.driver = driver
def find(self,locator):
"""
单个元素定位方法封装
:param locator: {"name":"xxx","by":"id","value":"xxx"}
:return: 定位方法
"""
print("正在通过 %s 属性 %s:定位>>%s"%(locator["by"],locator["value"],locator["name"]))
#text属性定位
if "text" in locator["by"]:
t_value = "//*[@text='%s']"%locator["value"]
t_xpath = ("xpath",t_value)
element = WebDriverWait(self.driver,30,0.5).\
until(EC.presence_of_element_located(t_xpath))
#content-desc属性定位
elif "desc" in locator["by"]:
element = WebDriverWait(self.driver,30,0.5).\
until(lambda x: x.find_element_by_accessibility_id(locator["value"]))
#uiautomator方法定位,value传值如:'text("登录")'
elif "uiautomator" in locator["by"]:
element = WebDriverWait(self.driver,30,0.5).\
until(lambda x: x.find_element_by_android_uiautomator(locator["value"]))
#其它属性定位方法:id,xpath,class
else:
e_locator = (locator["by"],locator["value"])
element = WebDriverWait(self.driver,30,0.5).\
until(EC.presence_of_element_located(e_locator))
return element
6、我的页面元素文件,创建my_page.py文件
class MyCodeLoginPage:
"""
我的-验证码登录页面元素
"""
my = {"name":"我的","by":"text","value":"我的"}
phone = {"name":"我的-手机号码","by":"text","value":"请输入11位手机号"}
code = {"name":"我的-验证码","by":"id","value":"com.tckk.kk:id/edit_identifying_code"}
code_button ={"name":"我的-验证码按钮","by":"id","value":"com.tckk.kk:id/identifying"}
login = {"name":"我的-登录按钮","by":"id","value":"com.tckk.kk:id/login"}
pwd_login = {"name":"我的-密码登录","by":"id","value":"com.tckk.kk:id/pwd_login"}
class MyPwdLoginPage:
"""
我的-密码登录页面元素
"""
phone = {"name":"我的-手机号码","by":"text","value":"请输入11位手机号"}
pwd = {"name":"我的-密码","by":"id","value":"com.tckk.kk:id/input_pwd"}
login_button = {"name":"我的-登录","by":"id","value":"com.tckk.kk:id/login"}
forget_pwd = {"name":"我的-忘记密码","by":"id","value":"com.tckk.kk:id/forget_pwd"}
back = {"name":"我的-返回","by":"id","value":"com.tckk.kk:id/back"}
7、测试代码,创建test_login1.py文件
import unittest
from appium import webdriver
from common.find_element import AppPage
from common.read_devices import app_device_cfg
from page.my_page import MyCodeLoginPage,MyPwdLoginPage
import time
#读取手机配置参数
devices = ["leidian", "vivo"]
a = []
for i in devices:
cfg = app_device_cfg(device=i)
a.append(cfg)
phone = ["15700000000","19911111111"]
class MyTestCase(unittest.TestCase):
"""
快快登录测试
"""
def setUp(self):
"""
初始化相关环境
:return:
"""
#启动app
element_1 = a.pop()
self.driver = webdriver.Remote("http://127.0.0.1:%s/wd/hub" % element_1["port"], element_1["des"])
self.element = AppPage(self.driver)
self.phone = phone.pop()
print(element_1)
self.driver.implicitly_wait(30)
def tearDown(self):
self.driver.quit()
def test_login(self):
"""
登录失败案例
:return:
"""
time.sleep(5)
self.element.find(MyCodeLoginPage.my).click()
self.element.find(MyCodeLoginPage.pwd_login).click()
time.sleep(5)
self.element.find(MyPwdLoginPage.phone).send_keys(self.phone)
self.element.find(MyPwdLoginPage.pwd).send_keys("123456")
self.element.find(MyPwdLoginPage.login_button).click()
#断言登录失败,还在登录页面
text = self.element.find(MyPwdLoginPage.forget_pwd).text
self.assertEqual(text,"忘记密码?")
if __name__ == '__main__':
unittest.main()
8、运行脚本,创建run_all_case.py文件
from tomorrow import threads
from common.start_appium import StartAppium
from case.test_login1 import MyTestCase
import unittest
#启动服务
host = "127.0.0.1"
for i in range(2):
port = 4723 + 2*i
StartAppium(host,port)
# #运行脚本,没有使用unittest框架
# devices = ["leidian","vivo"]
# pohe = ["15700000000","19911111111"]
# for i in range(len(devices)):
# run_app(deviceName=devices[i],pohe=pohe[i])
#unittest用例
# pohe = ["15777936597","19960378307"]
@threads(2) #添加线程
def run():
"""
读取用例,运行脚本
:return:
"""
suite = unittest.TestSuite()
suite.addTest(MyTestCase("test_login"))
runner = unittest.TextTestRunner()
runner.run(suite)
if __name__ == "__main__":
#循环运行
for i in range(2):
print(i)
run()