实践中发现,如果需要进行多机并发等情况时
执行机五花八门,各型号,各版本都有
如果配置针对每台机写死,工作量将非常的大,而且代码的通用性也不高。
其中执行机不同的地方在于 设备号及系统版本号。其余的参数是相同的,一份默认参数配置放置于yaml文件中
设备号可以通过adb 命令 "adb devices"中得到
系统版本号经过找了些资料也可以通过adb命令 "adb shell getprop ro.build.version.release" 得到系统版本号
翻了翻python的库发现 subprocess比os.system库好用,可以返回执行结果和错误信息
yaml文件:设置一个默认配置
automationName: UiAutomator2
platformName: Android
platformVersion: 7.1.2
deviceName: Android Emulator
appPackage: com.autonavi.minimap
appActivity: com.autonavi.map.activity.SplashActivity
noReset: True
实例:
获取设备名列表
In [1]: command = "adb devices"
In [2]: import subprocess
In [4]: out, err = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
In [5]: print(out) # bytes格式
b'List of devices attached\r\nemulator-5554\tdevice\r\n\r\n'
In [6]: print(err)
b''
In [7]: out = str(out, encoding="utf8") # 转化为str格式
In [8]: print(out)
List of devices attached
emulator-5554 device
In [13]: out = out.strip() # 去除头尾字符、空白符(包括\n、\r、\t、' ',即:换行、回车、制表符、空格)
In [14]: out = out.split("\r\n") # \r\n → r\n 为换行符,按行为单位进行切片
In [15]: print(out)
['List of devices attached', 'emulator-5554\tdevice']
In [16]: out.remove("List of devices attached") # 首行也含“device”,所以去除干扰信息
In [17]: uuid = [] # 声明用于存有效信息的列表
In [20]: for item in out:
...: print(item)
...: if "device" in item: # 判断设备是否为"device"这种正常状态
...: item = item.split("\t") # 将这行信息进行切片,以 \t制表符为单位
...: print(item)
...: uuid.append(item[0]) # 将切片好的设备名放入列表中
...:
...:
emulator-5554 device
['emulator-5554', 'device']
In [21]: print(uuid)
['emulator-5554']
In [22]: print(uuid[0]) # 使用时对列表进行遍历即可
'emulator-5554'
获取系统版本号列表
In [27]: uuid
Out[27]: ['emulator-5554']
In [28]: command = "adb -s {} shell getprop ro.build.version.release" # 通过指定设备号获取系统版本
In [33]: for id in uuid:
...: out, err = subprocess.Popen(command.format(id), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
...: print(out)
...: out = str(out, encoding="utf8")
...: b.append(out.strip("\r\n"))
...:
'7.1.2\r\n'
In [34]: b
Out[34]: ['7.1.2']
In [39]: list(zip(uuid, b))
Out[39]: [('emulator-5554', '7.1.2')] # 设备号与版本号的元组列表
cmd.py : 封装execute command的操作及信息
import subprocess
class Command:
def cmd_run(self, command):
try:
out, err = \
subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()
out = str(out, encoding="utf8").strip()
err = str(err, encoding="uft8").strip()
if err:
raise Exception("run command error")
except:
raise
else:
return out
def devices_and_version(self):
devices_uuid = self.__get_devices()
versions = self.__get_version()
res = list(zip(devices_uuid, versions))
return res
def __get_devices(self):
command = "adb devices"
res = self.cmd_run(command)
if "\r\n" in res: # windows newline == \r\n 针对不同系统
res = res.split("\r\n")
if "\n" in res: # linux newline == \n
res = res.split("\n")
res.remove("List of devices attached")
devices = []
for item in res:
if "device" in item:
device = item.split("\t")[0]
devices.append(device)
return devices
def __get_version(self):
uuids = self.__get_devices()
command = "adb -s {} shell getprop ro.build.version.release"
versions = []
for uuid in uuids:
version = self.cmd_run(command.format(uuid))
versions.append(version)
return versions
cmd = Command()
print(cmd.devices_and_version())
app自动化与GUI自动化多线程上有一点不同
app每次仅可启动一次,GUI浏览器对象可以启动多个
根据输入参数,灵活应用,自启动appium server服务
前提:安装appium server https://www.jianshu.com/p/2e06d1dc003c
appium server 命令行操作
start.py
import yaml
from appium import webdriver
from appium.webdriver.appium_service import AppiumService # 用于启动appium server
from command import Command
def base_args(*port, **kwargs):
file = "./conf/caps.yaml" # 设定yaml文件
with open(file, "r") as file:
caps = yaml.full_load(file)
cmd = Command()
info = cmd.devices_and_version()
n = 0
if kwargs:
for key, value in kwargs.items():
caps[key] = value
for res in info: # 若需要多台机可在此处进行多线程操作,本实例只涉及多设备运行
caps["deviceName"] = res[0]
caps["platformVersion"] = res[1]
service = AppiumService() # 实例化对象
if not port: # 如果未指定port则默认
port = ["4444"]
service.start(args=["-a", "127.0.0.1", "-p", port[n], "--session-override"], timeout_ms=2000) # 启动appium server 本来此处打算自己写的 后来发现appium库已经提供方法
driver = webdriver.Remote(command_executor='http://127.0.0.1:{}/wd/hub'.format(port[n]),
desired_capabilities=caps)
yield driver # 将驱动对象return出去
service.stop() # 关闭当前appium server