Appium实现多机测试

做android自动化的时候,启动一个appium服务,只能匹配一个手机去自动化执行。有时候想同一套代码,可以在不同的手机上执行,测下app在不同手机上兼容性。 这就需要启动多个appium服务了,并且android设备和appium要一一对应才行。

一、实现需求

1.为每一台设备准备两个端口号port和bp-port

  • 每一台手机需要在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

二、配置安卓SDK

点击查看

注意:如果已经安装则不需要安装

三、Appium-Desktop配置命令行启动

1.首先确认本机已经安装了nodeappium-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()
posted @ 2021-06-06 17:23  酒剑仙*  阅读(1139)  评论(0)    收藏  举报