Testcontainers WebDriver 容器实战:用 Docker 浏览器容器搞定 Selenium 3/4 UI 测试
【免费下载链接】testcontainers-javaTestcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.项目地址: https://gitcode.com/GitHub_Trending/te/testcontainers-java
本指南基于 Testcontainers Java 的 selenium 模块(org.testcontainers.selenium.BrowserWebDriverContainer),系统讲解如何在 JUnit 测试中自动启动、管理与销毁 Chrome / Firefox / Edge 浏览器容器,并获取RemoteWebDriver执行真实浏览器测试。读完本文,你将掌握浏览器容器的一键接入、宿主 Web 应用的访问方式、VNC 视频录制(全部录制 / 仅失败录制 / FLV 与 MP4 格式切换 / 自定义录制文件命名)以及底层实现原理,可直接复用到自己的 UI 自动化测试工程中。
为什么要在容器里跑浏览器测试
Testcontainers 可以直接实例化并管理包含浏览器(如 SeleniumHQ 的 docker-selenium 镜像)的容器,从而把"浏览器环境"从测试机中彻底抽离出来。其核心收益包括:
- API 兼容性:通过提供
RemoteWebDriver实例,完全兼容 Selenium 3 与 4 的 Chrome、Firefox 测试,以及 Selenium 4 的 Edge 测试; - 零本地依赖:测试服务器上无需预装浏览器,甚至不需要桌面环境,唯一的外部依赖是正常工作的 Docker 与你的 JUnit 测试套件;
- 环境固定、无漂移:浏览器始终从固定、干净的镜像启动,杜绝了用户手动修改或浏览器自动升级带来的配置漂移;
- 版本自动匹配:浏览器 Docker 镜像版本会与 classpath 上的
selenium-api-*.jar版本自动匹配(详见下文源码解析),保证浏览器版本与 Selenium API 兼容; - 状态隔离:每次使用全新浏览器,不会在测试之间泄漏 Cookie、缓存数据或其他状态;
- VNC 屏幕录制:Testcontainers 可以自动录制测试运行的视频,并支持只录制失败的测试,极大方便了问题复现与定位。
得益于浏览器容器创建速度很快,完全可以在每个测试都使用全新的浏览器实例,而不是复用有状态的浏览器进程。
快速上手:JUnit 中的 Chrome 容器
在你的 JUnit UI 测试类中声明如下字段,即可准备一个运行 Chrome 的容器(完整示例见 ChromeWebDriverContainerTest.java):
public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withNetwork(NETWORK);随后,不要在测试方法中直接new一个 WebDriver 实例,而是基于容器提供的 Selenium 地址创建远程驱动(见 LocalServerWebDriverContainerTest.java):
RemoteWebDriver driver = new RemoteWebDriver(chrome.getSeleniumAddress(), new ChromeOptions());拿到driver之后,就可以像使用普通 WebDriver 一样进行定位元素、点击、断言等操作。例如仓库测试基类 BaseWebDriverContainerTest.java 中的做法:
driver.get("http://helloworld:8080"); WebElement title = driver.findElement(By.tagName("h1")); assertThat(title.getText().trim()).isEqualTo("Hello world");浏览器容器、驱动会在测试方法结束(使用@Rule时)或测试类结束(使用@ClassRule时)后自动关闭回收。
测试宿主机上运行的 Web 应用
如果你的被测 Web 应用运行在宿主机(即运行 JUnit 测试的那台机器)上——这是非常常见的情形——那么浏览器容器无法直接访问localhost,需要借助 Testcontainers 的宿主机端口暴露特性。仓库测试中的完整写法如下:
// 暴露宿主机的 localPort 端口给容器 Testcontainers.exposeHostPorts(localPort); driver.get("http://host.testcontainers.internal:" + localPort);其中host.testcontainers.internal是 Testcontainers 提供的特殊主机名,用于让容器内进程访问宿主机服务。LocalServerWebDriverContainerTest中正是这样在容器内启动 Jetty 服务器、暴露随机端口后由 Chrome 容器访问并断言页面内容"It worked"的。
切换浏览器:Chrome、Firefox 与 Edge
目前支持 Chrome、Firefox 和 Edge 三种浏览器,切换方式非常简单——只需替换容器构造函数的第一个参数(镜像名):
// Chrome new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") // Firefox new BrowserWebDriverContainer("selenium/standalone-firefox:4.13.0") // Edge new BrowserWebDriverContainer("selenium/standalone-edge:4.13.0")分别参见 FirefoxWebDriverContainerTest.java(FirefoxOptions)与 EdgeWebDriverContainerTest.java(EdgeOptions)。注意:从源码看,容器会校验镜像与内置兼容列表(selenium/standalone-chrome、selenium/standalone-firefox、selenium/standalone-edge及其-debug变体)匹配,见 BrowserWebDriverContainer.java。
视频录制:失败回放与全程留痕
默认情况下不会录制视频,但你可以通过withRecordingMode让 Testcontainers 为全部测试或仅失败的测试录制屏幕(示例见 ChromeRecordingWebDriverContainerTest.java):
// 录制所有测试 BrowserWebDriverContainer chrome = new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withRecordingMode(VncRecordingMode.RECORD_ALL, target); // 仅录制失败的测试 BrowserWebDriverContainer chrome = new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withRecordingMode(VncRecordingMode.RECORD_FAILING, target);withRecordingMode的第二个参数必须是一个目录(视频将保存到该目录)。录制模式由 BrowserWebDriverContainer.VncRecordingMode 枚举定义,共三种:SKIP(跳过,也是新容器的默认值)、RECORD_ALL(全部录制)、RECORD_FAILING(仅失败录制)。
录制格式:FLV 与 MP4
默认录制为 FLV 格式,也可以通过withRecordingMode的三参重载显式指定或改为 MP4:
// 指定 MP4 格式 new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withRecordingMode(VncRecordingMode.RECORD_ALL, target, VncRecordingFormat.MP4) // 显式指定 FLV 格式 new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withRecordingMode(VncRecordingMode.RECORD_ALL, target, VncRecordingFormat.FLV)自定义录制文件命名
如果你希望根据测试描述以及测试成功/失败状态,在运行时自定义录制文件的文件名或保存目录,可以实现一个自定义的录制文件工厂:
BrowserWebDriverContainer chrome = new BrowserWebDriverContainer("selenium/standalone-chrome:4.13.0") .withRecordingFileFactory(new CustomRecordingFileFactory());注意:工厂类必须实现org.testcontainers.containers.RecordingFileFactory接口。仓库内置的 DefaultRecordingFileFactory.java 使用"%s-%s-%s.%s"的格式生成文件名,依次为PASSED/FAILED标记、测试的可文件系统友好名称、时间戳(YYYYMMdd-HHmmss)与格式扩展名,例如FAILED-recordingTestThatShouldBeRecordedAndRetained-20260915-123456.flv。
引入依赖
在pom.xml/build.gradle中加入以下依赖(将{{latest_version}}替换为你使用的 Testcontainers 版本):
=== "Gradle"groovy testImplementation "org.testcontainers:testcontainers-selenium:{{latest_version}}"=== "Maven"xml <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers-selenium</artifactId> <version>{{latest_version}}</version> <scope>test</scope> </dependency>
注意:添加 Testcontainers selenium 库 JAR不会自动添加 Selenium Webdriver JAR,你还需要确保项目中存在合适的 Selenium 依赖,例如:
=== "Gradle"groovy compile "org.seleniumhq.selenium:selenium-remote-driver:3.141.59"=== "Maven"xml <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-remote-driver</artifactId> <version>3.141.59</version> </dependency>
Testcontainers 会尝试将容器化浏览器的版本与 classpath 上检测到的 Selenium 版本进行匹配(版本号可依项目实际情况调整)。
源码级剖析:BrowserWebDriverContainer 内部实现
org.testcontainers.selenium.BrowserWebDriverContainer(见 BrowserWebDriverContainer.java)继承自GenericContainer并实现TestLifecycleAware,其在configure()中完成了一系列关键配置,理解这些有助于你排查问题:
- 端口与地址:固定暴露 Selenium 端口
4444与 VNC 端口5900;getSeleniumAddress()返回http://<host>:<mappedPort>/wd/hub供RemoteWebDriver连接,getVncAddress()返回形如vnc://vnc:secret@<host>:<mappedPort>的地址,可用 VNC 客户端实时观察浏览器画面(默认 VNC 密码为secret); - 版本匹配机制:旧版(已废弃)的
org.testcontainers.containers.BrowserWebDriverContainer会在启动时通过 SeleniumUtils.java 扫描 classpath 中selenium-apiJAR 的MANIFEST.MF(Build-Info/Selenium段下的Selenium-Version属性)来自动确定版本,并据此选择匹配的镜像 tag;新版 API 则要求显式传入带 tag 的镜像名,测试中使用的是4.13.0; - 就绪等待策略:默认采用
WaitAllStrategy,组合了LogMessageWaitStrategy(匹配RemoteWebDriver instances should connect to/Selenium Server is up and running等日志)与HostPortWaitStrategy,启动超时 1 分钟,见 getDefaultWaitStrategy; - 启动重试与稳定性:考虑到浏览器容器偶发的不稳定,设置
setStartupAttempts(3)允许最多 3 次启动尝试; - 共享内存:为避免浏览器容器内存不足,Linux 下将宿主
/dev/shm以读写方式挂载进容器,Windows 下则设置 512MB 共享内存; - 环境变量:注入
TZ(默认取user.timezone,缺失时为Etc/UTC),并保证no_proxy=localhost,避免 Selenium 通信被代理干扰; - 录制生命周期:非
SKIP模式下会启动VncRecordingContainer配合录制,afterTest()根据录制模式与测试是否抛异常决定是否保留视频,stop()时依次停止录制容器与浏览器容器。
仓库对应的测试覆盖了浏览器识别、简单页面探索、指定镜像名、自定义等待超时、无 capabilities 场景、录制时长校验(通过 ffmpeg 校验录制视频非零时长)等场景,可作为编写自身测试时的参考(见 modules/selenium/src/test 目录)。
结语
Testcontainers 的 WebDriver 容器把"浏览器环境"变成了测试代码中可编程、可回收的资源:无需本地浏览器、无需桌面环境,还能自动匹配 Selenium 版本、隔离测试状态,并在失败时留下可回放的视频证据。配合 ChromeWebDriverContainerTest.java 等测试示例,你可以很快将其整合进现有的 JUnit 4 / JUnit 5 或 Spock 测试套件,为你的 UI 自动化测试提供稳定、可复现的运行底座。
【免费下载链接】testcontainers-javaTestcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.项目地址: https://gitcode.com/GitHub_Trending/te/testcontainers-java
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考