Appium实现多机测试
做android自动化的时候,启动一个appium服务,只能匹配一个手机去自动化执行。有时候想同一套代码,可以在不同的手机上执行,测下app在不同手机上兼容性。 这就需要启动多个appium服务了,并且android设备和appium要一一对应才行。
一、实现需求
-
每一台手机需要在PC端启动2个线程,每个线程都需要1个端口。
-
端口号前提没被占用
2.检测端口是否被占用
对于上面的端口号可以利用以下命令来检测是否被其他占用
netstat -ano | findstr {port}
3.利用多线程去分别为每一台设备启动2个线程
-
一个线程用于运行测试脚本,一个线程用于运行Appium Server。
-
先启动Appium Server最后再运行脚本。由于Appium Server启动慢,所以待该线程启动一段时间后,方可启动测试脚本。
#Appium Server启动命令 start /b appium -a 127.0.0.1 -p {port} -bp {bp_port} --session-override
1.首先确认本机已经安装了node和appium-desktop(注意appium在安装时要选择为所有用户安装,而不是只为本人安装,否则会有权限问题)

2.确认本机安装的appium的路径,然后在appium安装路径下找到resources\app\node_modules\appium。

3.找到自己的npm目录,默认是C:\Users\你的用户名\AppData\Roaming\npm(这个目录是个隐藏目录,你可以进了C:\Users\你的用户名这个路径后在浏览器的路径栏自己把路径补充完整),在该目录下创建node_modules目录(如果已经有该目录了则不需要重建)
4.在node_modules目录下直接创建一个文本文件,文件名命名为appium,后缀改为cmd。文件里面的具体内容需要根据大家自己安装appium的路径来修改,比如,我的appium是安装到C:\Program Files\Appium下的,就写成:
@IF EXIST "%~dp0\node.exe" ( "%~dp0\node.exe" "C:\Program Files\Appium Server GUI\resources\app\node_modules\appium\build\lib\main.js" %* ) ELSE ( @SETLOCAL @SET PATHEXT=%PATHEXT:;.JS;=;% node "C:\Program Files\Appium Server GUI\resources\app\node_modules\appium\build\lib\main.js" %* )
然后保存即可。
5.重新打开一个命令行,这输入appium,如果出现下面的提示则表示配置成功:
onenote.py
from appium import webdriver class OneNoteAccount: def __init__(self, port, deviceName, platformVersion): self.desired_caps = { 'platformName': 'Android', # 被测手机是安卓 'platformVersion': platformVersion, # 手机安卓版本 'deviceName': deviceName, # 设备名,安卓手机可以随意填写 'appPackage': 'com.mobivans.onestrokecharge', # 启动APP Package名称 'appActivity': 'com.mobivans.onestrokecharge.activitys.MainActivity', # 启动Activity名称 'unicodeKeyboard': True, # 使用自带输入法,输入中文时填True 'resetKeyboard': True, # 执行完程序恢复原来输入法 'noReset': True, # 不要重置App 'newCommandTimeout': 60000, 'udid': deviceName # 'automationName': 'UiAutomator1' } # 连接Appium Server,初始化自动化环境 self.driver = webdriver.Remote(f'http://127.0.0.1:{port}/wd/hub', self.desired_caps) def business(self): # 设置缺省等待时间 self.driver.implicitly_wait(20) # 点击 加号 self.driver.find_element_by_xpath( "//android.widget.LinearLayout[@resource-id='com.mobivans.onestrokecharge:id/main_write1']/android.widget.ImageView").click() # 点击 日常 按钮 self.driver.find_element_by_xpath( "//android.support.v7.widget.RecyclerView[@resource-id='com.mobivans.onestrokecharge:id/add_rv_cateGrid']/android.widget.LinearLayout[1]/android.widget.TextView").click() # 添加备注 self.driver.find_element_by_id("com.mobivans.onestrokecharge:id/add_et_remark").send_keys("购买了毛衣") # 输入 金额 45 self.driver.find_element_by_id("com.mobivans.onestrokecharge:id/keyb_btn_4").click() self.driver.find_element_by_id("com.mobivans.onestrokecharge:id/keyb_btn_5").click() # 点击 完成 按钮 self.driver.find_element_by_id('com.mobivans.onestrokecharge:id/keyb_btn_finish').click() if __name__ == '__main__': OneNoteAccount(4723, '127.0.0.1:62001', '7.1.2').business()
MultiMachineTest.py
import os import time import threading from onenote import OneNoteAccount class MultiMachineCompatibilityTest: # 获取当前系统连接的所有设备信息 def get_devices_info(self): # 定义一个port port = 4723 bp_port = 4724 # 首先取出 当前连接的设备信息 devices = os.popen("adb devices").read().strip().split("\n") # 从读取出来的结果列表中去除下标为0的元素 devices.pop(0) # 定义一个列表,用来保存设备信息 devices_information = [] # 取出的设备信息放在了一个列表中,变量列表,然后取出设备名称,在根据设备名称,取出设备版本 for dev in devices: # 获取设备名称 device_name = dev.split('\t')[0] # 根据上面的设备名称(例如:127.0.0.1:21503),获取出设备的安卓系统版本信息 platform_version = \ os.popen(f"adb -s {device_name} shell getprop ro.build.version.release").read().strip().split("\n")[0] # 添加到列表中 # 保存之前先判断该端口是否可用,如果被占用则可以先清除端口, self.check_port(port) self.check_port(bp_port) devices_information.append((port, bp_port, device_name, platform_version)) # 设置端口的自增 port += 10 bp_port += 10 return devices_information # 检查端口是否可用, def check_port(self, port): cmd = f"netstat -ano | findstr {port}" # 执行命名 获取执行形象 res = os.popen(cmd).read() # 如果能查出来,则不为空 if len(res) != 0 and 'LISTENING' in res: # 如果有多行信息,根据\n切片操作, 取出该端口所对应的端口 pid = res.split("\n")[0].split(" ")[-1] print(pid) print(f"{port} 端口被占用,即将杀掉该接口对应进程{pid}") # 结束进程 resp = os.popen(f"taskkill -f -pid {pid}").read() if '成功' in resp: print(f"端口{port}已经被成功清理") return True else: print(f'{port} 端口可用') return True print(f"端口{port}任然处于被占用的状态,请检查!") return False def appium_start(self, port, bp_port, device_name, platform_version): """ :param port: appium service端口号 :param bp_port: bootstrip端口号 :param device_name: 设备名称(例如:127.0.0.1:52503) :param platform_version: 版本(例如:7.12) """ ''' start /b appium -a 127.0.0.1 -p {port} -bp {bp_port} --session-override start:启动 /b:后台线程 -a 是指定监听的ip(也可写成 --address),后面“127.0.0.1”可以改为你需要的ip地址; -p 是指定监听的端口(也可写成 --port),也可以修改为你需要的端口; -bp:是连接Android设备bootstrap的端口号(也可写成–bootstrap-port) --session-override 是指覆盖之前的session; ''' cmd = f"start /b appium -a 127.0.0.1 -p {port} -bp {bp_port} --session-override" print(f"{cmd} at {time.ctime()}") # 执行命令 os.system(cmd) time.sleep(30) # 执行业务测试代码 OneNoteAccount(port, device_name, platform_version).business() def thread_start_appiumsevice(self): # 先调用方法获取当前的连接设备信息,一个设备启动一个appium sevice与之对应 devices_list = self.get_devices_info() print(devices_list) time.sleep(3) # [(4723, 4724, '127.0.0.1:21503', '7.1.2'), (4733, 4734, '127.0.0.1:21513', '7.1.2')] for device in devices_list: # 注意 这里要用多线程操作 t = threading.Thread(target=self.appium_start, args=(int(device[0]), int(device[1]), device[2], device[3])) # # 启动线程,每一个线程对应一个appium service t.start() if __name__ == '__main__': # 启动service MultiMachineCompatibilityTest().thread_start_appiumsevice()



浙公网安备 33010602011771号