Docker+Selenium Grid构建分布式UI自动化测试集群实战指南
1. 项目概述与核心价值如果你正在为UI自动化测试执行缓慢、环境配置繁琐、多浏览器兼容性测试头疼那么今天分享的这个“Docker Selenium Grid”组合方案绝对是你工具箱里不可或缺的利器。我经历过太多项目从单机脚本跑几个小时到后来团队协作时环境不一致导致的“在我机器上好好的”窘境最终这套方案成了我们团队的测试基础设施标配。它本质上解决的是通过容器化技术将Selenium Grid的分布式测试能力标准化、轻量化让你能像搭积木一样快速构建起一个支持并行、跨浏览器、且环境一致的自动化测试集群。简单来说Docker负责封装和交付标准化的测试环境而Selenium Grid负责调度和分发测试任务。你不再需要在一台台机器上手动安装Java、浏览器、驱动也不用担心不同测试人员环境差异导致的结果不一致。通过几个Docker命令你就能在几分钟内拉起一个包含Chrome、Firefox、Edge等多种浏览器的测试网格然后你的自动化脚本只需要告诉Grid“我要一个Chrome”Grid就会自动把任务分配到空闲的、装有Chrome的容器节点上去执行。这对于需要快速反馈的持续集成流水线或者需要进行大规模回归测试的场景效率提升是数量级的。接下来我会从一个实践者的角度带你从零开始一步步拆解如何搭建、配置、使用这个分布式测试环境并分享我们在实际项目中踩过的坑和总结出的最佳实践。无论你是测试开发工程师、DevOps还是对自动化测试感兴趣的后端开发这篇内容都能让你获得一套可直接复现的完整方案。2. 环境整体设计与架构解析在动手敲命令之前理解整个架构的设计思路至关重要。这能帮助你在遇到问题时知道该从哪个环节去排查也能让你根据自己团队的实际需求进行灵活的调整。2.1 为什么是Docker Selenium Grid传统的UI自动化测试尤其是需要多浏览器并行时通常面临几个痛点环境配置地狱每台测试机都需要安装特定版本的JDK、浏览器、浏览器驱动如chromedriver版本匹配是个精细活一旦出错脚本就无法运行。资源利用率低单台机器通常只能串行执行测试用例或者通过多线程模拟并行但受限于单机硬件资源CPU、内存、网络并发数有上限且浏览器实例间可能相互干扰。维护成本高浏览器版本升级需要同步更新所有测试机上的驱动测试机操作系统差异也会带来额外适配工作。难以集成CI/CD在Jenkins、GitLab CI等工具中动态准备和清理测试环境比较麻烦。Docker的引入完美解决了环境一致性与便携性问题。Selenium官方维护的docker-selenium镜像已经将Selenium Server、浏览器、驱动以及必要的依赖如字体、显示服务器打包好。你拉取一个镜像运行一个容器就是一个立即可用的、隔离的浏览器测试环境。Selenium Grid则解决了任务调度与资源池化的问题。它采用经典的Hub-Node中心-节点架构Hub 作为大脑和调度中心。它不执行任何测试只负责接收来自自动化测试脚本的请求并根据请求中描述的“能力”Capabilities如浏览器类型、版本、平台等将请求转发给注册到它这里、且符合要求的Node。Node 作为执行单元。每个Node都是一个独立的测试执行环境上面运行着Selenium Server以及一种或多种浏览器。Node启动后会向Hub注册告知Hub自己具备哪些“能力”例如“我能提供Chrome 125.0”。当你的测试脚本通过RemoteWebDriver连接到Hub时Hub会根据脚本的需求从注册的Node中挑选一个合适的建立连接后续的所有浏览器操作指令都会由Hub转发给该Node执行。将两者结合Docker负责快速、批量地生产出标准化的Node甚至Hub而Grid负责高效地管理和利用这些Node资源。你可以轻松地在一台性能强劲的服务器上运行多个浏览器容器作为Node实现单机多并发也可以将Node分布在多台物理机上实现真正的分布式并发突破单机资源限制。2.2 核心组件与网络规划在部署前我们需要规划好各个组件的角色、位置以及它们之间的网络通信。Hub容器 通常一个集群只需要一个Hub。你需要将它运行在一个所有Node和测试执行机都能访问到的主机上。Hub默认监听4444端口用于WebDriver协议通信和4442/4443端口用于内部事件总线通信。Node容器 你可以运行任意多个Node。每个Node容器需要知道Hub的地址SE_EVENT_BUS_HOST以便注册。Node会暴露5555端口用于与Hub通信以及5900端口用于VNC远程查看调试用。测试执行机 运行你自动化测试脚本Python pytest、Java TestNG等的机器。它只需要能通过网络访问到Hub的4444端口即可完全不需要安装任何浏览器或驱动。网络模式选择 这是实践中的一个关键决策点。场景A所有容器跑在同一台宿主机本地开发/快速验证。方案使用Docker默认的bridge网络或者更简单的使用docker-compose。容器间通过容器名或自定义网络互通非常方便。此时SE_EVENT_BUS_HOST可以设置为Hub的容器名如selenium-hub。场景BNode分布在多台不同的物理机/虚拟机生产级分布式。方案Hub运行在一台主机上并将端口映射到主机网络-p 4442-4444:4442-4444。Node运行在其他主机上启动时SE_EVENT_BUS_HOST必须设置为Hub宿主机的真实IP地址确保跨主机网络可达。重要提醒务必确保宿主机防火墙开放了相关端口4442-4444, 5555, 5900否则容器间无法通信。实操心得在规划初期我强烈建议先从“单机多容器”模式开始使用docker-compose来管理这能极大简化网络配置和生命周期管理。等整个流程跑通后再扩展到多机部署。一开始就搞多机网络问题可能会让你寸步难行。3. 实战搭建从零构建分布式测试集群理论清晰后我们进入实战环节。我会以最常用的“单机部署Hub和多个Node”为例因为这是学习和中小项目中最实用的场景。多机部署的原理完全相同只是IP地址需要替换为实际的主机IP。3.1 基础环境准备首先确保你的机器上已经安装了Docker和Docker Compose。这是所有操作的前提。对于LinuxUbuntu/CentOS 通过官方脚本或包管理器安装即可。安装后记得将当前用户加入docker用户组避免每次命令都要sudo。# 以Ubuntu为例安装Docker Engine sudo apt-get update sudo apt-get install docker.io sudo systemctl start docker sudo systemctl enable docker # 安装Docker Compose插件Docker新版本已集成 sudo apt-get install docker-compose-plugin # 将当前用户加入docker组 sudo usermod -aG docker $USER # 退出终端重新登录生效对于Windows/macOS 直接下载并安装 Docker Desktop 。它自带了Docker Engine、CLI和Compose。安装完成后通常需要重启电脑。验证安装docker --version docker-compose --version # 或 docker compose version3.2 使用Docker Compose一键部署手动docker run每个容器虽然直观但参数多管理麻烦。docker-compose.yml文件能让我们用声明式的方式定义和运行多容器应用是管理Selenium Grid集群的绝佳工具。创建一个名为docker-compose.yml的文件内容如下version: 3.8 services: selenium-hub: image: selenium/hub:latest container_name: selenium-hub ports: - 4442:4442 - 4443:4443 - 4444:4444 environment: - SE_EVENT_BUS_PUBLISH_PORT4442 - SE_EVENT_BUS_SUBSCRIBE_PORT4443 - SE_OPTS--log-level FINE # 可选设置Hub日志级别调试时有用 networks: - selenium-grid chrome-node: image: selenium/node-chrome:latest container_name: chrome-node depends_on: - selenium-hub environment: - SE_EVENT_BUS_HOSTselenium-hub - SE_EVENT_BUS_PUBLISH_PORT4442 - SE_EVENT_BUS_SUBSCRIBE_PORT4443 - SE_NODE_MAX_SESSIONS4 # 单个Node最大并发会话数 - SE_NODE_OVERRIDE_MAX_SESSIONStrue - SE_VNC_NO_PASSWORD1 - SE_START_VNCtrue volumes: - /dev/shm:/dev/shm # 挂载宿主机共享内存解决浏览器崩溃问题 shm_size: 2g # 另一种设置共享内存大小的方式与上面volumes二选一即可 ports: - 5901:5900 # 将容器5900映射到主机5901避免端口冲突 - 5555:5555 networks: - selenium-grid firefox-node: image: selenium/node-firefox:latest container_name: firefox-node depends_on: - selenium-hub environment: - SE_EVENT_BUS_HOSTselenium-hub - SE_EVENT_BUS_PUBLISH_PORT4442 - SE_EVENT_BUS_SUBSCRIBE_PORT4443 - SE_NODE_MAX_SESSIONS4 - SE_NODE_OVERRIDE_MAX_SESSIONStrue - SE_VNC_NO_PASSWORD1 - SE_START_VNCtrue volumes: - /dev/shm:/dev/shm shm_size: 2g ports: - 5902:5900 # 映射到主机5902 - 5556:5555 # 映射到主机5556避免与chrome-node冲突 networks: - selenium-grid networks: selenium-grid: driver: bridge关键配置解析网络Networks 我们创建了一个名为selenium-grid的自定义桥接网络。所有服务hub, chrome-node, firefox-node都加入这个网络。在这个网络里容器间可以通过服务名如selenium-hub直接通信这是最简洁的方式。Hub配置 暴露了4442-4444端口到宿主机。环境变量SE_EVENT_BUS_PUBLISH_PORT和SE_EVENT_BUS_SUBSCRIBE_PORT明确指定了事件总线端口与端口映射保持一致。Node配置SE_EVENT_BUS_HOSTselenium-hub Node通过这个主机名在Docker网络内找到Hub。这是单机部署的关键你不需要知道宿主机的IP。SE_NODE_MAX_SESSIONS 这个参数决定了该Node容器能同时运行多少个浏览器实例。设置它需要综合考虑容器分配的内存、CPU以及测试用例的资源消耗。对于Chrome/Firefox4是一个比较保守且通用的起步值。我们的经验是一个分配了2核4G内存的容器跑4个Chrome会话比较稳定。SE_NODE_OVERRIDE_MAX_SESSIONStrue 必须设置为true上述最大会话数的配置才会生效。shm_size: 2g和volumes: - /dev/shm:/dev/shm这是解决Docker容器内浏览器崩溃的最重要配置Chrome和Firefox会使用/dev/shm共享内存进行进程间通信。Docker容器默认的64MB共享内存通常不够会导致浏览器崩溃。这里我们通过shm_size参数将容器内的/dev/shm大小设置为2GB。挂载宿主机的/dev/shm是另一种等效做法通常选其一即可。端口映射 我们将chrome-node的VNC端口5900映射到宿主机的5901firefox-node的映射到5902这样可以通过不同的端口分别访问两个节点的VNC界面。5555端口也做了区分映射避免冲突。在包含docker-compose.yml文件的目录下执行以下命令启动整个集群docker-compose up -d-d参数表示后台运行。执行后Docker会拉取镜像如果本地没有并启动所有容器。使用docker-compose ps查看服务状态确保所有容器都是Up状态。访问http://localhost:4444你应该能看到Selenium Grid的控制台页面。刚开始可能看不到Node等待十几秒刷新一下如果配置正确chrome-node和firefox-node就会注册上来。3.3 验证与调试使用Grid控制台和VNCGrid控制台http://localhost:4444是你的管理面板。在这里你可以查看所有已注册的Node及其能力浏览器、版本、平台。查看当前正在执行的会话Sessions。配置队列等高级参数通常默认即可。VNC远程查看 这是调试UI自动化测试的“上帝视角”。当测试脚本在Node容器中操作浏览器时你可以实时看到浏览器画面。下载一个VNC Viewer客户端如RealVNC VNC Viewer。在VNC Viewer中连接地址。对于我们的配置Chrome节点localhost:5901Firefox节点localhost:5902连接时因为我们设置了SE_VNC_NO_PASSWORD1所以密码留空即可。连接成功后你会看到一个干净的桌面当有测试任务在该节点执行时浏览器窗口就会在这里出现。注意事项 VNC功能虽然强大但会消耗额外资源。在生产环境的CI/CD流水线中通常不需要开启VNC。可以通过设置SE_START_VNCfalse来禁用它以节省资源。仅在调试或需要录制测试视频时开启。4. 编写并执行分布式自动化测试环境就绪后我们需要编写能够连接到Grid的测试脚本。这里以Pythonpytest和JavaTestNG两种最流行的语言为例。4.1 Python pytest 实现并行测试Python生态中pytest是测试框架的事实标准结合pytest-xdist插件可以轻松实现测试用例的并行执行。第一步安装依赖pip install pytest selenium pytest-xdist第二步编写测试脚本test_grid_demo.py这里的关键是使用webdriver.Remote来连接Grid Hub并通过DesiredCapabilities或新版Options来指定浏览器能力。import pytest from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.desired_capabilities import DesiredCapabilities import time # 定义Hub的地址 HUB_URL http://localhost:4444/wd/hub pytest.fixture(scopefunction) def driver(request): 为每个测试函数提供一个远程WebDriver实例。 使用request.param来参数化浏览器类型。 browser request.param if browser chrome: # 方法1使用DesiredCapabilities传统方式仍可用 # capabilities DesiredCapabilities.CHROME.copy() # 方法2使用Options推荐更现代支持更多配置 options webdriver.ChromeOptions() # 可以添加浏览器选项例如无头模式 # options.add_argument(--headless) # options.add_argument(--no-sandbox) # options.add_argument(--disable-dev-shm-usage) # 在Docker中建议添加 driver webdriver.Remote(command_executorHUB_URL, optionsoptions) elif browser firefox: options webdriver.FirefoxOptions() # options.add_argument(-headless) driver webdriver.Remote(command_executorHUB_URL, optionsoptions) else: raise ValueError(fUnsupported browser: {browser}) yield driver # 测试结束后退出浏览器释放Node上的会话资源 driver.quit() # 使用pytest的parametrize装饰器让测试函数对chrome和firefox两个参数各运行一次 pytest.mark.parametrize(driver, [chrome, firefox], indirectTrue) def test_search_on_baidu(driver): 一个简单的测试用例访问百度并搜索关键词。 try: driver.get(https://www.baidu.com) # 显式等待通常比time.sleep更好这里为了示例简单使用sleep time.sleep(2) search_box driver.find_element(By.ID, kw) search_box.send_keys(Docker Selenium Grid) search_box.submit() time.sleep(3) # 简单的断言检查页面标题是否包含搜索词 assert Docker Selenium Grid in driver.title print(fTest passed for {driver.capabilities[browserName]}) except Exception as e: print(fTest failed for {driver.capabilities[browserName]}: {e}) raise第三步使用pytest-xdist并行执行在终端中进入脚本所在目录运行pytest test_grid_demo.py -v -n 2-v: 显示详细输出。-n 2: 指定使用2个worker进程并行执行。pytest-xdist会收集到两个测试项因为参数化然后用两个worker同时执行它们。执行过程解析pytest启动2个worker进程。第一个worker执行test_search_on_baidu(driverchrome)。它向http://localhost:4444/wd/hub发起请求要求一个Chrome浏览器。Hub收到请求查看注册的Node发现chrome-node有能力提供Chrome于是将请求转发给它。chrome-node容器内启动一个Chrome实例并返回一个会话ID给Hub再传回给worker1的脚本。后续所有driver.xxx的操作都会通过Hub转发到chrome-node的这个Chrome实例上。与此同时第二个worker执行test_search_on_baidu(driverfirefox)过程类似但请求会被Hub分配给firefox-node。这样两个测试用例就在不同的浏览器、不同的容器中真正并行执行了。你可以在Grid控制台看到两个活跃的会话也可以用VNC分别连接到5901和5902端口观察两个浏览器的实时操作。4.2 Java TestNG 实现并行测试Java生态中TestNG是支持并发测试非常成熟的框架。第一步项目依赖Mavenpom.xmldependencies dependency groupIdorg.seleniumhq.selenium/groupId artifactIdselenium-java/artifactId version4.15.0/version !-- 使用较新版本 -- /dependency dependency groupIdorg.testng/groupId artifactIdtestng/artifactId version7.8.0/version scopetest/scope /dependency /dependencies第二步编写测试基类与测试用例// BaseTest.java import org.openqa.selenium.WebDriver; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Parameters; import java.net.MalformedURLException; import java.net.URL; public class BaseTest { protected WebDriver driver; protected static final String HUB_URL http://localhost:4444/wd/hub; BeforeMethod Parameters(browser) public void setUp(String browser) throws MalformedURLException { DesiredCapabilities capabilities new DesiredCapabilities(); capabilities.setBrowserName(browser); // 从testng.xml接收浏览器参数 // 可以设置版本、平台等更多能力 // capabilities.setVersion(125.0); // capabilities.setPlatform(Platform.LINUX); driver new RemoteWebDriver(new URL(HUB_URL), capabilities); driver.manage().window().maximize(); } AfterMethod public void tearDown() { if (driver ! null) { driver.quit(); } } }// GridDemoTest.java import org.openqa.selenium.By; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.annotations.Test; import java.time.Duration; public class GridDemoTest extends BaseTest { Test public void testBaiduSearch() { driver.get(https://www.baidu.com); WebDriverWait wait new WebDriverWait(driver, Duration.ofSeconds(10)); wait.until(ExpectedConditions.presenceOfElementLocated(By.id(kw))); driver.findElement(By.id(kw)).sendKeys(TestNG Selenium Grid); driver.findElement(By.id(su)).click(); wait.until(ExpectedConditions.titleContains(TestNG Selenium Grid)); Assert.assertTrue(driver.getTitle().contains(TestNG Selenium Grid)); System.out.println(Test passed on browser: ((RemoteWebDriver) driver).getCapabilities().getBrowserName()); } }第三步配置TestNG XML文件以实现并行创建testng.xml文件配置并行执行策略。!DOCTYPE suite SYSTEM https://testng.org/testng-1.0.dtd suite nameSelenium Grid Suite paralleltests thread-count2 !-- paralleltests 表示以test标签为单位并行 -- !-- thread-count2 表示最大并发线程数为2 -- test nameChrome Test parameter namebrowser valuechrome/ classes class nameGridDemoTest/ /classes /test test nameFirefox Test parameter namebrowser valuefirefox/ classes class nameGridDemoTest/ /classes /test /suite第四步执行测试你可以使用IDE如IntelliJ IDEA直接运行testng.xml或者通过Maven命令执行mvn test -DsuiteXmlFiletestng.xmlTestNG会启动两个线程分别执行两个test从而同时向Grid请求Chrome和Firefox浏览器实现并行测试。5. 高级配置、优化与故障排查基础搭建和脚本编写只是第一步要让这套系统在生产环境中稳定、高效地运行还需要一些进阶的配置和优化技巧。5.1 指定浏览器版本与规模化部署使用特定版本的浏览器镜像 测试常常需要锁定特定的浏览器版本。selenium/node-chrome:latest标签可能随时变化。你应该使用固定版本的镜像。去 Docker Hub 查找需要的标签例如selenium/node-chrome:120.0。在docker-compose.yml中修改image字段chrome-node: image: selenium/node-chrome:120.0 # ... 其他配置保持不变使用docker-compose扩展Node数量 如果你想快速增加同类型浏览器的节点数量以提升并发能力docker-compose的scale命令非常方便。# 将chrome-node扩展到3个实例 docker-compose up -d --scale chrome-node3Compose会自动为新的容器实例生成唯一的名称如projectname_chrome-node_1,projectname_chrome-node_2它们都会注册到同一个Hub上。你可以在Grid控制台看到多个提供相同能力的Chrome节点。5.2 性能调优与稳定性保障SE_NODE_MAX_SESSIONS设置 这个值不是越大越好。它受限于容器分配的资源CPU、内存。一个经验法则是观察单个浏览器实例在执行测试时的内存占用可以通过docker stats命令观察容器内存。为容器分配的内存 / 单个实例内存占用 ≈ 最大会话数。并预留一部分内存给操作系统和Selenium Server本身。例如容器分配了4G内存一个Chrome会话峰值占用800MB那么SE_NODE_MAX_SESSIONS设置为4比较安全。盲目设置成10会导致容器内存耗尽OOM被系统杀死。会话超时与清理 测试脚本异常退出可能导致浏览器会话没有正常quit()这些“僵尸会话”会一直占用Node资源。Grid有自动清理机制但你可以通过环境变量调整SE_NODE_SESSION_TIMEOUT 设置会话超时时间秒默认300。超时后Grid会强制清理该会话。在你的测试框架中务必在tearDown或AfterMethod、AfterTest等钩子中确保driver.quit()被调用。使用无头模式Headless 在CI/CD流水线中通常不需要图形界面。使用无头模式可以显著减少资源消耗提高执行速度。在Python的Options中添加add_argument(--headless)。在Java的DesiredCapabilities或Options中设置。注意 无头模式下无法使用VNC查看调试时可以先关闭此选项。5.3 常见问题与排查实录即使按照步骤操作你也可能会遇到一些问题。这里记录了几个我们团队高频遇到的坑和解决方法。问题1Node启动成功但在Grid控制台看不到状态为Unreachable现象 Node容器日志显示已启动并尝试注册但Hub控制台显示Node不可用。排查网络不通 这是最常见的原因。检查Node容器内是否能ping通Hub的地址。在单机docker-compose部署中确保SE_EVENT_BUS_HOST设置的是服务名如selenium-hub并且所有服务在同一个自定义网络中。在多机部署中检查防火墙是否放行了4442、4443、5555端口。端口映射错误 确保Hub的4442和4443端口正确映射到了宿主机并且Node配置的SE_EVENT_BUS_PUBLISH_PORT和SE_EVENT_BUS_SUBSCRIBE_PORT与Hub映射出来的端口一致。查看Hub和Node日志 使用docker logs -f selenium-hub和docker logs -f chrome-node查看实时日志通常会有明确的错误信息。问题2测试脚本能连接到Hub但无法启动浏览器报SessionNotCreatedException现象 脚本抛出异常提示无法创建新会话。排查Node资源不足 检查Node的SE_NODE_MAX_SESSIONS是否已满。Grid控制台会显示每个Node的“最大会话数”和“当前会话数”。浏览器驱动不匹配 如果你使用了非latest标签的镜像或者自行构建了镜像确保容器内的浏览器版本和驱动版本匹配。官方镜像通常已经匹配好。共享内存/dev/shm不足 这是导致浏览器在容器内崩溃的元凶。务必确保在docker run命令或docker-compose.yml中设置了足够的shm-size如2g或挂载了宿主机的/dev/shm。问题3测试执行速度慢或者偶尔超时现象 测试用例执行时间远长于本地或出现TimeoutException。排查网络延迟 如果Hub、Node和测试执行机分布在不同的机器甚至不同的机房网络延迟会显著影响指令传输速度。尽量让它们处于同一个低延迟的网络内。Hub成为瓶颈 在超高并发如上百个会话下单Hub可能成为瓶颈。可以考虑Selenium Grid的“完全分布式”模式或者使用更强大的机器运行Hub。优化测试脚本 避免在远程执行中使用大量的time.sleep()改用显式等待WebDriverWait。减少不必要的页面截图、日志输出等操作。问题4如何查看实时运行的浏览器画面方案 使用VNC。确保Node容器启动时设置了SE_START_VNCtrue和SE_VNC_NO_PASSWORD1或设置密码并将容器的5900端口映射到宿主机。使用VNC Viewer连接宿主机IP:映射端口即可。这在调试元素定位、验证操作流程时非常有用。问题5想录制测试视频怎么办方案 Selenium Grid官方镜像的Node本身就支持视频录制。通过环境变量SE_RECORD_VIDEOtrue可以开启。录制好的视频文件会保存在容器内的/videos目录你可以通过挂载卷volumes的方式将其持久化到宿主机。chrome-node: image: selenium/node-chrome:latest environment: - SE_RECORD_VIDEOtrue volumes: - ./videos:/videos # 将宿主机当前目录下的videos文件夹挂载到容器/videos测试结束后视频文件会自动生成在宿主机的./videos目录下。6. 集成到CI/CD流水线将Docker Selenium Grid集成到Jenkins、GitLab CI、GitHub Actions等CI/CD工具中可以实现自动化测试的常态化运行。核心思路动态创建测试环境 在Pipeline的某个阶段例如post { always { ... } }或专门的测试阶段使用docker-compose up -d命令启动Selenium Grid集群。等待服务就绪 启动后需要添加一个健康检查步骤确保Hub和Node完全启动并可以接受请求。一个简单的方法是循环调用Hub的/status端点http://hub-host:4444/status直到返回成功。执行测试 在环境就绪后运行你的pytest或TestNG测试套件。测试脚本中Hub的地址应配置为CI环境中的服务名或IP例如在Docker Compose网络中就是selenium-hub。收集结果与清理 测试完成后收集测试报告和日志如pytest-html报告、Allure报告。最后无论测试成功与否在Pipeline的最后阶段使用docker-compose down命令清理所有容器释放资源。一个简化的GitLab CI.gitlab-ci.yml示例stages: - test ui-automation: stage: test image: python:3.9-slim # 使用一个包含Docker客户端的镜像或自定义镜像 services: - docker:dind # 使用Docker-in-Docker服务允许在CI作业中运行Docker命令 variables: DOCKER_HOST: tcp://docker:2375 DOCKER_DRIVER: overlay2 before_script: - apk add --no-cache docker-compose - pip install pytest selenium pytest-xdist pytest-html script: # 1. 启动Selenium Grid集群 - docker-compose up -d # 2. 等待Hub就绪简单轮询 - | echo Waiting for Selenium Hub to be ready... for i in seq 1 10; do curl -s http://selenium-hub:4444/status | grep -q ready break sleep 3 done # 3. 执行测试生成HTML报告 - pytest test_grid_demo.py -v -n 2 --htmlreport.html --self-contained-html # 4. 测试完成后清理环境 after_script: - docker-compose down artifacts: when: always paths: - report.html reports: junit: report.xml # 如果生成了JUnit格式报告这套流程确保了每次代码提交都能在一个全新的、一致的环境中运行UI自动化测试极大地提高了测试的可靠性和可信度。

相关新闻