zoukankan      html  css  js  c++  java
  • app自动化测试----多设备并行运行

    1. 总结

    app自动化测试---多台设备并行运行monkey(subprocss 子进程方式 && multiprocessing 多进程方式)

    app自动化测试----使用Python代码启动和关闭 一个/多个设备Appium

    app自动化测试---- pytest 多设备连接,并行执行测试用例(pytest 通过设置变量的方式传参)

    2.样例代码展示

    main.py  (项目运行文件

    """
      项目运行文件,并添加测试报告
    """
    import pytest
    import os,time
    import multiprocessing
    from utils.adb_handler import get_connect_devices
    
    def run(device):
        # 进程启动之后设置变量
        os.environ['udid'] = str(device[0])
        os.environ['port'] = str(device[1])
    
        report_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'reports')
        if not os.path.exists(report_dir):
            os.mkdir(report_dir)
    
        report = time.strftime('%Y-%m-%d_%H-%M-%S') + '_' + str(device[1])
    
        reportfile = os.path.join(report_dir, report + '.html')
    
        pytest.main(['testcases', '-s', '-v', f'--html={reportfile}'])
    
    
    
    if __name__ == '__main__':
        # 获取所有的连接设备
        devices = get_connect_devices()
        process = []
    
        for device in devices:
            #创建进程
            p = multiprocessing.Process(target=run,args=(device,))
            p.start()
            process.append(p)
    
        for proc in process:
            proc.join()

    conftest.py  (pytest配置文件

    from appium import webdriver
    import os, time,pytest
    from utils.adb_handler import start_appium, stop_appium
    from utils.file_handler import FileHandler
    
    chromedriver= os.path.join(os.path.dirname(os.path.abspath(__file__)),'drivers/chrome/75.0.3770.140/chromedriver.exe')
    
    # scope='session' 标记的方法执行域为---->所有测试用例运行之前/之后 运行的方法
    @pytest.fixture(scope='session',autouse=True)
    def driver():
        # 启动appium服务
        port = os.environ['port']
        start_appium(port)
    
        desired_caps = {
            'platformName': 'Android',                    # 测试Android系统
            'udid': os.environ['udid'],                   # adb devices 命令查看  设置为自己的设备
            'automationName': 'UiAutomator2',             # 自动化引擎
            'noReset': False,                             # 不要重置app的状态
            'fullReset': False,                           # 不要清理app的缓存数据
            'chromedriverExecutable': chromedriver,       # chromedriver 对应的绝对路径
            'appPackage': "org.cnodejs.android.md",       # 应用的包名
            'appActivity': ".ui.activity.LaunchActivity"  # 应用的活动页名称(appium会启动app的加载页)
        }
        driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_capabilities=desired_caps)
        driver.implicitly_wait(5)  # 全局的隐式等待时间
        yield driver  # 将driver 传递出来
        # 所有的用例执行之后
        driver.quit()
        stop_appium(port)
    
    
    # 该方法是用来获取测试用例执行的结果(passed / FAILED)
    @pytest.hookimpl(tryfirst=True,hookwrapper=True)
    def pytest_runtest_makereport(item, call):
        outcome = yield
        rep = outcome.get_result()               # 获取用例的执行结果
        # print('用例的执行结果rep---->',rep)
        setattr(item, "rep_" + rep.when, rep)    # 将执行结果保存到 item 属性中 , req.when 执行时
    
    
    # scope='function' 标记的方法执行域为---->每个测试用例运行之前/之后 运行的方法
    @pytest.fixture(scope='function',autouse=True)
    def case_run(driver:webdriver,request):   # request 为 pytest_runtest_makereport 方法获取到的执行结果(固定参数和用法)
        yield
        if request.node.rep_call.failed:
            file_handler = FileHandler()
            screenshots = file_handler.save_file_dir('img')
            casename: str = request.node.nodeid
            # print("执行测试用例的名字:", casename)
            # 测试用例的名字很长 testcases/test_ddt/test_ddt_login.py::TestDdtLogin::test_login[....]
            # 对字符串进行截取,截取之后显示为  test_ddt_login-TestDdtLogin
            casename = casename[casename.rfind('/')+1:casename.rfind('::')].replace('.py', '').replace('::', '-')
            filename = time.strftime('%H_%M_%S') + '-' + casename +".png"
            screenshot_file = os.path.join(screenshots, filename)
            # 保存截图
            driver.save_screenshot(screenshot_file)

    utils/adb_handler.py   (adb命令处理文件类)

    """
      adb命令处理文件类
    """
    import subprocess
    import os,sys,time
    from utils.file_handler import FileHandler
    from config import appoum_port
    
    file_handler = FileHandler()
    logs_dir = file_handler.save_file_dir('log')
    
    # 获取所有的连接设备
    def get_connect_devices():
        devices = []
        port = appoum_port
        proc = subprocess.Popen('adb devices',stdout=subprocess.PIPE,shell=True)
        for line in proc.stdout.readlines():
            # 将字节类型转换为字符串
            line_str = line.decode(encoding='utf8')
            if '	device' in line_str:
                # 字符串分割 提取 deviceid值
                device_id = line_str.strip().split('	device')[0]
                devices.append((device_id,port))
                port += 2
        print('devices连接设备----》', devices)
        return devices
    
    
    # 使用命令行的方式启动appium
    def start_appium(port):
        """
        启动appium 服务
        :param port: 服务的端口号
        :return:
        """
        stop_appium(port)
        cmd = f"appium -p {port}"
        logsdir = file_handler.save_file_dir('log')
        log_name = time.strftime('%Y_%m_%d') + '-appium_log-' +  str(port) +".log"
        appium_logs_dirName = os.path.join(logsdir,log_name)
        with open(appium_logs_dirName, mode='a', encoding="utf8") as file:
            subprocess.Popen(cmd, shell=True, stdout=file,stderr=subprocess.PIPE)
    
    
    # 使用命令行的方式关闭appium
    def stop_appium(port):
        mac_cmd = f"lsof -i tcp:{port}"
        win_cmd = f"netstat -ano | findstr {port}"
        # 判断操作系统
        os_platform = sys.platform
        print('操作系统:',os_platform)
        # #windows 系统
        if os_platform == "win32":
            win_p = subprocess.Popen(win_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            for line in win_p.stdout.readlines():
                if line:
                    line = line.decode('utf8')
                    if "LISTENING" in line:
                        win_pid = line.split("LISTENING")[1].strip()
                        os.system(f"taskkill -f -pid {win_pid}")
        else:
            # unix系统
            p = subprocess.Popen(mac_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            for line in p.stdout.readlines():
                line = line.decode('utf8')
                if "node" in line:
                    stdoutline = line.split(" ")
                    # print(stdoutline)
                    pid = stdoutline[4]
                    os.system(f"kill {pid}")
    
  • 相关阅读:
    新项目反思
    nei网访问
    react
    css沉默
    沉默
    node准备
    C++学习(八):删除文件
    利用工具格式化日期文本
    PageHelper 记录总条数不正确问题处理
    tk.mybatis 多个or条件拼接
  • 原文地址:https://www.cnblogs.com/Z-Queen/p/14977687.html
Copyright © 2011-2022 走看看