• web自动化测试——跨平台设备管理方案Selenium Grid


    一、Selenium Grid简介

    Selenium Grid 是 Selenium 的三大组件之一,它可以在多台机器上并行运行测试,集中管理不同的浏览器版本和浏览器配置。通过将客户端命令发送到远程浏览器的实例, Selenium Grid 允许在远程计算机 (虚拟或真实) 上执行 WebDriver 脚本. 它旨在提供一种在多台计算机上并行运行测试的简便方法。

    官方文档:https://www.selenium.dev/

    二、使用场景

    场景一: 实现分布式执行测试,提高执行效率

    比如:我们有 1000 条用例执行,如果在本机执行,一条用例耗时 100 秒,执行完成则需要大约 27 小时 1000*100/60/60=27个小时。如果让这些用例并发执行,比如分配 6 台计算机,每个计算机执行 1000/6 大约 166 条用例,那时间大约节省了 6 倍,原来需要大约 27 个小时,现在可能只需要 4.5 个小时左右就基本完成了, 分布式并发执行可以让我们用例的执行总时长指数级的缩小,从而效率得到很大的提升。

    场景二: 解决浏览器兼容性问题

    比如还是 1000 条用例,需要分别在 Chrome、Firefox、Edge、Safari 这些浏览器上都执行一遍,保证每个浏览器上都能正常执行,测试浏览器的兼容性。这时也可以使用 Selenium Grid,通过 Selenium Grid 将这些请求分发到不同的系统、不同浏览器中执行。这些浏览器可以分别布署在不同的计算机中比如可以布署在 Linux 、Windows、Mac 上都可以,作为它的 Node 结点,从而解决兼容性测试的问题

    新特性

    Selenium Grid 4 是一个全新的工具,它能够支持完全分布式的测试。Selenium Grid4 也兼容了之前 Selenium Grid3 的工作模式,在 Selenium Grid3 的基础上又添加了一些新的通讯方式,使它通讯速度更快。另外现在很多公司都支持容器化部署,Selenium Grid 4 也提供了的 Docker 支持。相比 Selenium Grid 3,Selenium Grid 4 更容易在虚拟机上使用。

    Selenium Grid4 有三个新特性
    特性一:Hub 和 Node 使用同一个 jar 服务。
    特性二:架构优化,在 Selenium Grid 4 版本的全新架构中划分成了组件:Router、Distributor、Node、Session Map、Session Queue、Event Bus。
    特性三:支持不同的运行模式,Selenium 4 支持三种网格类型,包括 Standalone Mode 独立模式、Classical Grid 经典网格模式、Fully Distributed 完全分布式

    三、Selenium Grid4原理分析

    在这里插入图片描述
    从图中可以看到 Selenium Grid 包括六大组件,分别是:

    Router 路由器
    Distributor 分发服务器
    Session Map 会话映射
    Node 测试节点
    New Session Queue 新的会话队列
    Event Bus 事件总线

    下面分别说一下这六个组件所负责的职责:
    Router 路由器:Router 是所有组件的入口,所有向服务器发送的外部请求第一个会经常 Router 组件。
    Distributor 分发服务器:它有两个主要的功能,第一个功能,注册并跟踪所有 Node 节点,第二个功能就是查询新会话队列并处理挂起的新会话请求。当一个新的请求到达 Router 时,它会被转发到 New Session Queue,在队列中等待。分发服务器会轮询新会话队列查找挂起的新会话请求,为这个请求找到匹配的节点之后,会创建一个新的会话,这个会话的 ID 以及 URI 会存储在 Session Map 中。
    Session Map 会话映射:它是一个数据存储区,它存储了会话 ID 与对应的会话结点的关系,在 Router 转发请求到对应的结点时,要先在 Session Map 中查看对应的关系,再进行请求。
    Node 测试节点:结点有多个,每个结点管理多个可用的浏览器的插槽,结点只负责执行命令,不需要做出其它的判断。这个 Node 可以配置在 Windows、Mac、Linux 等任何系统上。
    New Session Queue 新的会话队列:从 Router 发过来的请求,它会先放到这个队列中, 等待被分发服务器分发出去,这个队列有一些特殊的功能,它能够定期的检查会话是否超时,如果超时,请求将被拒绝并立即删除。这里可以配置一些参数来处理超时时长等参数。
    Event Bus 事件总线:充当了节点、分发服务器、新会话队列和会话映射之间的通信路径,使用了 socket 通信。在完全分布式模式下启动 selenium grid 时,事件总线会是第一个被启动起来的组件。

    四、环境安装

    Java11 及以上版本。
    下载被测试的浏览器(Chrome/Firefox/Edge/Safari 等)。
    配置环境变量,将对应的 driver 提前下载下来配置到环境变量中。或者将下载的 driver 放在与 selenium server 的 jar 包同级目录下也可以。
    Selenium Server 下载,建议使用 4.4.0 版本。

    五、运行方式:单机运行 - 独立模式

    1. 命令行启动 server

    在这里插入图片描述

    2. java -jar 启动对应的 jar 包

    java -jar selenium-server-.jar standalone

    java -jar selenium-server-4.9.0.jar standalone
    
    • 1

    启动成功后,对应命令行显示:Started Selenium Standalone …,如图

    在这里插入图片描述

    3. 查看 UI 界面 > 浏览器输入网址查看 UI 界面:UI 链接

    在这里插入图片描述

    4. 代码运行

    直接运行代码,发现在本地运行单线程,只不过通过 Selenium Grid 来转发请求。

    a、运行步骤

    SeleniumGrid 会创建一个 Queue 队列,里面包含了启动的参数代码

    Capabilities:
    
    {
      "acceptInsecureCerts": false,
      "browserName": "chrome",
      "browserVersion": "110.0.5481.178",
      "chrome": {
        "chromedriverVersion": "110.0.5481.30 (aedb656755c469651f01505a4f15e153fc606a1e-refs/branch-heads/5481@{#191})",
        "userDataDir": "C:\\Users\\Lenovo\\AppData\\Local\\Temp\\scoped_dir39460_2141646508"
      },
      "goog:chromeOptions": {
        "debuggerAddress": "localhost:58868"
      },
      "networkConnectionEnabled": false,
      "pageLoadStrategy": "normal",
      "platformName": "Windows 10",
      "proxy": {},
      "se:bidiEnabled": false,
      "se:cdp": "ws://192.168.22.1:4444/session/233f82cf555e0511765e5dc868cb1a84/se/cdp",
      "se:cdpVersion": "110.0.5481.178",
      "setWindowRect": true,
      "strictFileInteractability": false,
      "timeouts": {
        "implicit": 0,
        "pageLoad": 300000,
        "script": 30000
      },
      "unhandledPromptBehavior": "dismiss and notify",
      "webauthn:extension:credBlob": true,
      "webauthn:extension:largeBlob": true,
      "webauthn:virtualAuthenticators": true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    b、SeleniumGrid 创建一个本地的 session,然后再打开浏览器运行测试用例:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2023/5/14 15:08
    # @Author  : 杜兰特
    # @File    : test_grid.py
    from selenium.webdriver import DesiredCapabilities
    from selenium.webdriver import Remote
    
    class TestGrid:
    
        def test_grid(self):
            hub_url='http://127.0.0.1:4444/wd/hub'
            capability=DesiredCapabilities.CHROME.copy()
            for i in range(1,5):
                driver=Remote(command_executor=hub_url,desired_capabilities=capability)
                driver.get("http://www.baidu.com")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    5. 单浏览器运行代码

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2023/5/14 15:08
    # @Author  : 杜兰特
    # @File    : test_grid.py
    
    from time import sleep
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    class TestSingleNode:
        def setup_method(self):
            # 创建Options ,新版本DesireCapability已弃用
            options = webdriver.ChromeOptions()
            # 通过URL和options 创建一个远程的连接
            # client 发送请求,要发送给selenium grid hub 结点, hub 结点会将请求分发到对应的node
    
            self.driver = webdriver.Remote(
                command_executor='http://127.0.0.1:4444/wd/hub',
                options=options
            )
    
        def test_singlenode1(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("firefox")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "firefox" in self.driver.page_source
    
        def teardown_method(self):
            self.driver.quit()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    6、多浏览器运行代码

    创建测试文件 test_multi_node.py 示例代码如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 2023/5/14 16:25
    # @Author  : 杜兰特
    # @File    : test_multi_node.py
    
    from time import sleep
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    
    class TestMultiNode:
        def setup_method(self):
            options = webdriver.ChromeOptions()
            self.driver = webdriver.Remote(
                command_executor='http://127.0.0.1:4444/wd/hub',
                options=options
            )
    
        def test_multinode1(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("selenium")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "selenium" in self.driver.page_source
    
        def test_multinode2(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("appium")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "appium" in self.driver.page_source
    
        def test_multinode3(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("pytest")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "pytest" in self.driver.page_source
    
        def test_multinode4(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("requests")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "requests" in self.driver.page_source
    
        def test_multinode5(self):
            # 打开 baidu 页
            self.driver.get("http://www.baidu.com")
            # 向输入框中输入
            self.driver.find_element(By.ID, 'kw').send_keys("java")
            # 点击搜索框
            self.driver.find_element(By.ID, 'su').click()
            # 等待一秒
            sleep(1)
            # 断言输入内容在页面中
            assert "java" in self.driver.page_source
    
        def teardown_method(self):
            self.driver.quit()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    为了模拟多浏览器并发运行,使用 pytest 的插件 pytest-xdist 实现分布式并发执行方式,提前安装 pytest-xdist 插件,然后使用命令执行用例。打开命令提示行或者终端,使用cd 命令进入到文件所在路径,然后执行 pytest test_multi_node.py -n 3 --alluredir ./results命令。执行完用例之后,会把测试报告结果统一汇总到results 目录中。

    在这里插入图片描述

    六、单机运行 - 经典网格模式

    1. 命令行启动hub

    a、命令行 cd 到当前下载 jar 包的路径下

    b、java -jar 以 Hub 启动对应的 jar 包

    java -jar selenium-server-.jar hub

    java -jar selenium-server-4.9.0.jar hub
    
    • 1

    在这里插入图片描述
    此时,启动了 Router,Distributor,Session Map,New Session Queue,Event Bus;虽然,已经有了对应集线器,但是还没有 node 节点注册进来。
    如果不把节点 Node 注册进来,对应的集线器无法知道哪个物理机器可以被分发请求,对应的 Router 就无法把测试用例进行分发。

    在这里插入图片描述

    2. 命令行启动node

    a. 同一机器上启动 node

    java -jar selenium-server-.jar node --detect-drivers true

    java -jar selenium-server-4.9.0.jar node --detect-drivers true
    
    • 1

    在这里插入图片描述

    此时 node 节点创建成功,并且 hub 上注册对应 node 节点

    在这里插入图片描述

    健康检测就是每隔 2 分钟会 ping 一下对应 URL 看看是否可以 ping 成功,对应是否处于活动状态

    b. 再次查看状态的 UI 界面:

    在这里插入图片描述

    c. 代码运行

    直接运行代码,发现在本地运行单线程,只不过通过 Selenium Grid 来转发请求。

    七、多系统运行 - 分发模式(待补充)

    在经典网格模式等基础上再在其他机器上启动一个 node 角色。

    1. 不同机器上启动 node

    不同机器上启动 node:java -jar selenium-server-.jar node --detect-drivers true --publish-events tcp:// --subscribe-events tcp://

  • 相关阅读:
    RabbitMQ(安装配置以及与SpringBoot整合)
    错误: 找不到或无法加载主类 Main
    js深浅拷贝
    HTML静态网页成品作业(HTML+CSS)——图书出版社介绍设计制作(6个页面)
    Mybatis动态SQL
    P问题、NP问题、NPC问题和NP-Hard问题,相关概念与题目
    ubuntu中使用 vscode 连接docker开发环境
    2023年Q3线上生鲜水产数据分析:市场不景气,销额同比下滑44%
    美团动态线程池实践思路开源项目(DynamicTp),线程池源码解析及通知告警篇
    Linux/Windows Redis的下载与安装
  • 原文地址:https://blog.csdn.net/YZL40514131/article/details/133981358