Selenium 开发指南:用 Bazel 与 ./go 构建、测试并发布多语言语言绑定
2026/9/6 15:47:35 网站建设 项目流程

Selenium 开发指南:用 Bazel 与 ./go 构建、测试并发布多语言语言绑定

【免费下载链接】seleniumA browser automation framework and ecosystem.项目地址: https://gitcode.com/GitHub_Trending/se/selenium

本文基于 Selenium 官方仓库根目录的 README.md 展开,系统讲解作为 Selenium 贡献者需要准备的环境、Bazel 构建体系、各语言绑定(Java / Python / Ruby / Rust)的开发与测试流程,以及文档生成与发布(Releasing)的完整命令链路。读完后你将能够独立搭建 Selenium 本地开发环境、执行bazel build/bazel test等核心命令,并使用./goRake 封装完成从构建到发布的日常工作。

1. 这个仓库是什么:Selenium 伞项目与 W3C WebDriver 基础设施

README 开篇给出了一句最著名的口号:"Automates browsers. That's it!"。Selenium 是一个"伞项目"(umbrella project),封装了多种用于 Web 浏览器自动化的工具与库,其核心定位为W3C WebDriver 规范的基础设施实现——一个平台无关、语言无关、兼容所有主流浏览器(Chrome、Firefox、Edge、Safari、IE)的编码接口。

仓库顶层目录清晰地体现了这一"多语言绑定 + 构建基建"的组织方式:

目录内容
java/Java 绑定与 Grid 服务端(selenium-server / standalone jar)
py/Python 绑定(selenium 包)
dotnet/.NET 绑定
rb/Ruby 绑定(selenium-webdriver gem)
javascript/Node.js 绑定(selenium-webdriver)与 atoms
rust/Rust 实现的 Selenium Manager
cpp/遗留的 IEDriver、webdriver-interactions 等 C++ 组件
common/共享资源:Web 测试页面、Bidi/DevTools 协议 schema、镜像等

需要特别注意的是 README 的声明:这份 README 面向希望为项目贡献代码的开发者。如果你是初次使用 Selenium 的用户,应查阅官方 User Manual 获取示例与描述。本文严格沿袭这一定位,聚焦"如何在本仓库中构建与开发"。

2. 环境准备:从 Bazelisk + JDK 到 Windows 手动配置

2.1 所有平台的公共依赖

README 列出的本地开发环境依赖只有两项核心项:

  1. Bazelisk——Bazel 的包装器。它会自动读取仓库根目录的 .bazelversion 文件,下载其中指定的 Bazel 版本(当前仓库锁定为9.1.0),并将所有命令行参数透明地转发给真正的 Bazel 二进制。这意味着你只需安装 Bazelisk 一次,无需手动跟随项目升级 Bazel。
  2. Java JDK 17 或更高版本(例如 Java 17 Temurin)。注意两点:
    • 必须把JAVA_HOME指向 JDK(而非 JRE)的可执行文件位置;
    • 验证方法是运行javac:如果只装了 JRE,该命令不存在;如果看到一串命令行选项输出,说明 JDK 引用正确。

从源码结构看,.bazelrc 中还配置了--java_runtime_version=remotejdk_25,即 Bazel 构建过程中会拉取 JDK 25 工具链来编译目标产物(默认--release 11字节码级别),这与本机 JDK 17 的要求并不冲突:本机 JDK 供 Rake/go等脚本运行,构建工具链由 Bazel 自行管理。

2.2 macOS 平台

  • 安装Xcode 及命令行工具xcode-select --install
  • Apple Silicon 机器需要Rosetta:在.bazelrc.local文件中添加build --host_platform=//:rosetta

这个 Rosetta 平台在根目录 BUILD.bazel 中有对应定义——一个约束为os:osx + cpu:x86_64platform规则,供 Apple Silicon 上以 x86_64 方式运行 host 构建时使用。README 也注明团队正致力于长期消除这一要求。

2.3 Windows 平台:自动脚本与手动配置两条路线

Windows 上 Bazel 的依赖较多(MSYS2 提供 bash、VS C++ 构建工具、长路径支持等),README 提供了两个选项:

选项 1:从零自动安装。以管理员身份打开 PowerShell 后执行:

Set-ExecutionPolicy Bypass -Scope Process -Force

然后在目标目录下载并执行仓库自带的 scripts/dev-environment-setup.ps1。该脚本会保证得到一个"开箱即跑"的完整开发环境(已存在的组件不会被重复安装,除非提示)。

选项 2:手动安装。完整步骤如下:

  1. 允许运行 Selenium 仓库内的脚本:Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

  2. 启用开发者模式:

    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
  3. 安装MSYS2(提供类 Unix 命令行的 shell 环境):

    • 把 bin 目录加入PATH(例如"C:\tools\msys64\usr\bin");
    • bash.exe位置设为BAZEL_SH环境变量(例如"C:\tools\msys64\usr\bin\bash.exe")。
  4. 安装最新版Visual Studio Community

    • 通过安装器添加 "Desktop development with C++" 工作负载;
    • 将 Visual C++ 构建工具安装目录设为BAZEL_VC(例如"C:\Program Files\Microsoft Visual Studio\2022\Community\VC");
    • 将 Visual C++ Build Tools 版本号设为BAZEL_VC_FULL_VERSION(可从"$BAZEL_VC\Tools\MSVC\<BAZEL_VC_FULL_VERSION>"的目录名中查出)。
  5. 启用长文件名支持(Bazel 有大量超过 Windows 默认路径长度限制的嵌套目录):

    reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor" /t REG_DWORD /f /v "DisableUNCCheck" /d "1" reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /t REG_DWORD /f /v "LongPathsEnabled" /d "1"
    • 允许 Bazel 为长路径创建短名版本:fsutil 8dot3name set 0
    • 把 Bazel 输出目录从项目内嵌套目录改到C:/tmp:创建selenium/.bazelrc.windows.local文件,写入startup --output_user_root=C:/tmp

    .bazelrc 顶部两行try-import %workspace%/.bazelrc.localtry-import %workspace%/.bazelrc.windows.local正是为这类本地化覆盖文件预留的入口。

2.4 替代开发环境:GitPod、Dev Container 与 Docker 镜像

如果不想在本地搭环境,README 提供了三种"云端/容器化"替代方案:

  • GitPod:提供开箱即用的在线开发环境,无需本地配置。
  • Dev Container:本质是一个 Docker 容器,仓库提供了 .devcontainer/devcontainer.json。查看该文件可以看到其构建直接指向 scripts/dev-image/Dockerfile,即 Dev Container 与 Docker 镜像两条路线复用同一份 Dockerfile。VS Code、IntelliJ IDEA 等支持 Dev Container 的 IDE 会引导你创建容器。
  • Docker 镜像:直接使用 scripts/dev-image/Dockerfile 构建一个适合构建与测试 Selenium 的镜像。

2.5 多 Worktree 协作:让 Bazel 缓存"随取随用"

README 专门用一节讲Using Worktrees,这是一个很实用的贡献者技巧:Bazel 默认把构建输出和下载的依赖放在每个 checkout 之下,因此使用多个 git worktree 时会重复下载依赖、重复构建。解决办法是在用户级/path/to/your/home/.bazelrc中添加:

common --disk_cache=/path/to/your/home/.cache/bazel-disk common --repository_cache=/path/to/your/home/.cache/bazel-repo
  • --disk_cache存储编译 action 的输出;
  • --repository_cache存储下载的外部依赖(如http_archive压缩包)。

两个目录会随时间无限增长,磁盘紧张时应定期清理;并且建议把缓存放在与 checkout 相同的文件系统上,这样 Bazel 可以 hardlink 而非复制。

另一个容易踩的坑是output base:Bazel 会为每个 checkout 路径创建独立的 output base(编译产物、分析缓存、Bazel server),且删除 worktree 时它不会被自动清理——频繁创建/销毁 worktree 会泄漏数 GB 的陈旧输出。macOS/Linux 上可以让 worktree "自清理":在该 worktree 的.bazelrc.local中添加

startup --output_base=.local/output-base

.local/目录既被 gitignore 也出现在.bazelignore中(见 .bazelignore),删除 worktree 时 output base 随之消失,而上面共享的--disk_cache/--repository_cache仍然跨 worktree 共享。Windows 用户则应继续保留startup --output_user_root=C:/tmp(如 2.3 节所述)以避免路径长度限制,不要在仓库内更深嵌套 output base。

3. 构建体系:Bazel 命令、目标命名与 ./go 封装

3.1 为什么用 Bazel

Selenium 统一使用 Bazel 作为构建工具,README 给出的理由是:用它来统一管理依赖下载、生成必需的二进制、构建与发布打包、执行测试——且"快速、高效"。

3.2 四个最常用的 Bazel 命令

README 列出的核心命令:

命令作用
bazel build解析依赖、编译源文件、为指定目标生成输出文件,用于产出可执行文件、库或其他产物
bazel run先构建目标再执行它,通常用于产出可执行二进制的目标
bazel test构建并以带额外测试功能(测试运行器、沙箱、缓存)的上下文运行目标
bazel query查询给定路径下可用的目标

3.3 目标(target)命名规则

每个可构建模块由一个BUILD.bazel文件定义。执行模块时,目标引用格式为://+ 定义文件相对路径 +:+ 目标名。README 举的例子是构建 Grid:

bazel build //java/src/org/openqa/selenium/grid:executable-grid

查看根目录 BUILD.bazel 可以看到,仓库为此提供了根级 alias,于是构建 Grid 可以简写为:

bazel build grid

该 alias 的actual正是//java/src/org/openqa/selenium/grid:executable-grid,与 README 描述完全一致(构建日志会输出输出 jar 的位置)。此外 BUILD.bazel 还定义了selenium-server-standalonealias,指向//java/src/org/openqa/selenium/grid:selenium_server_deploy.jar

按语言批量构建:

bazel build //<language>/...

3.4 ./go:Rake 封装的命令入口

README 指出,很多 Bazel 命令都被自定义的 Rake wrapper 包装,通过仓库根目录的./go命令执行,例如构建某个语言的全部绑定:

./go <language>:build

从源码看,go 脚本本身非常薄:它设置若干--add-opensJVM 参数后,用third_party/jruby/jruby-complete.jar启动 JRuby 并执行rake <task>;真正的任务逻辑在 Rakefile 及各语言任务文件中。Rakefile 按语言加载命名空间任务:

namespace(:java) { load 'rake_tasks/java.rake' } namespace(:rb) { load 'rake_tasks/ruby.rake' } namespace(:py) { load 'rake_tasks/python.rake' } namespace(:python) { load 'rake_tasks/python.rake' } # alias namespace(:node) { load 'rake_tasks/node.rake' } namespace(:dotnet) { load 'rake_tasks/dotnet.rake' } namespace(:rust) { load 'rake_tasks/rust.rake' }

所以./go java:build./go py:install./go rb:console这类"语言:任务"语法,本质上是 JRuby 驱动的 Rake 任务分发。Rakefile 中还有一个值得注意的规则:任何看起来像 Bazel 目标(以//开头)的任务名,都会被直接转交给bazel build执行。此外 Rakefile 还内置了all:build/all:docs/all:release/all:format等跨语言聚合任务(例如 Rakefile 的all:build会依次调用五种语言绑定的 build 任务),这正是第 5 节发布流程的基础。

4. 分语言开发实践

4.1 Java

  • IntelliJ:团队日常主力 IDE。推荐安装 Bazel IJ 插件,并把仓库作为 Bazel 项目导入,view 文件使用 scripts 目录下的ij.bazelproject(macOS/Linux)或ij-win.bazelproject(Windows)。

  • Lint:使用 Google Java Format,配合 IntelliJ 的 Google Java Formatter 插件(配置步骤需查其官方文档);也可以直接运行自动格式化脚本./scripts/format.sh

  • 本地安装到 Maven 仓库:虽然 Selenium 不用 Maven 构建,但可以把构件部署到本地~/.m2/repository供 Maven 项目使用:

    ./go java:install
  • 更新依赖:依赖版本统一声明在 MODULE.bazel 中(bzlmod 模块,声明了 rules_java、rules_python、rules_ruby、rules_rs 等各语言 ruleset 以及 protobuf、llvm 等)。更新某个依赖版本后执行:

    RULES_JVM_EXTERNAL_REPIN=1 bazel run @maven//:pin

    或一键自动更新并重新 pin:

    ./go java:update

    查看 MODULE.bazel 可以看到仓库对 protobuf 做了single_version_override锁定(要求与预编译 protoc 版本配对),这类精细的版本治理都集中在这一个文件里。

4.2 Python

  • Lint 与格式化:遵循 PEP 8 风格指南(唯一例外:行长放宽到 120 字符),用 ruff 检查与强制;同样可用./scripts/format.sh一键自动格式化。

  • 从源码本地运行(不打包安装):

    pip install -r py/requirements_lock.txt ./go py:local_dev

    py:local_dev会构建生成文件(Bidi 协议类等生成代码)并拷贝到本地源码树,之后就可以从py目录直接import selenium

  • 构建并安装 wheel

    ./go py:install

    该命令尝试安装到全局site-packages,可能没有写权限,README 建议在安装前创建并激活一个虚拟环境。

4.3 Ruby

  • 替代irb的交互式 REPL(自动加载全部 gems):

    bazel run //rb:console
  • 调试:使用debuggem。步骤为:

    1. 在断点位置写入binding.break

    2. ruby_debug配置运行测试:bazel test --config ruby_debug <test>

    3. 调试器启动后,在另一个终端连接:

      bazel-selenium/external/bundle/bin/rdbg -A

      这个ruby_debug配置并非凭空而来:查看 .bazelrc 可以看到test:ruby_debug被定义为--test_output=streamed --test_env=RUBY_DEBUG_FORK_MODE=parent --run_under="@bundle//bin:rdbg --nonstop --open --command",即通过--run_under把 rdbg 调试器挂到测试进程前。

  • RubyMine:把rb/作为主项目目录打开;从selenium父目录运行./go rb:local_dev生成最新产物;在Settings / Languages & Frameworks / Ruby SDK and Gems中新增 Interpreter,指向../bazel-selenium/external/rules_ruby++ruby+ruby/dist/bin/ruby。此后即可运行与调试任意 spec,默认使用 Chrome,可通过 rb/TESTING.md 中说明的环境变量切换浏览器。

4.4 Rust

Rust 侧的 Bazel 依赖是直接从rust/Cargo.tomlrust/Cargo.lock生成的,贡献者改依赖时只需维护这两个 Cargo 文件,无需手写 Bazel 依赖规则。

5. 测试:Bazel 测试配置、过滤策略与 Linux 无头方案

5.1 常用测试参数

README 给出的一组测试常用参数(原文列表完整保留):

参数说明
--pin_browsers=false改用 Selenium Manager 定位浏览器/驱动(默认使用仓库 pin 的版本)
--headless以无头模式运行浏览器(支持 Chrome、Edge、Firefox)
--flaky_test_attempts 3失败的测试最多重跑 3 次
--local_test_jobs 1控制测试并行度
--cache_test_results=no/-t-禁用测试结果缓存,全部重跑
--test_output all打印测试的全部输出,而不只是错误
--test_output streamed逐个串行运行测试并立即打印输出
--test_env FOO=bar向测试进程传递额外环境变量
--run_under="xvfb-run -a"在执行前插入的前缀命令

这两个自定义 flag(--pin_browsers--headless)不是普通布尔开关,而是通过 .bazelrc 中的flag_alias映射到仓库内定义的 bool_flag。查看 common/BUILD.bazel 可以看到:pin_browsers默认值为True(测试默认用 pin 的浏览器),headless默认False,并配有对应的config_settinguse_pinned_browser/use_headless_browser),各语言测试目标据此选择驱动与浏览器启动参数。

5.2 按大小与 tag 过滤测试

Selenium 测试按 size 分为三档:

  • small——通常是单元测试,不打开浏览器;
  • large——通常是真正驱动浏览器的测试;
  • medium——比简单单元测试复杂,但不完整驱动浏览器。

按 size 过滤:

bazel test //<language>/... --test_size_filters=small

按 tag 过滤(注意负号前缀表示排除):

bazel test //<language>/... --test_tag_filters=this,-not-this

README 特别提醒:如果同时给出多个--test_tag_filters,只有最后一个生效——在继承了某个 config 时要格外小心。

各语言的测试细节写在对应目录的TESTING.md中,如 java/TESTING.md、py/TESTING.md、rb/TESTING.md。以 Python 为例,py/TESTING.md 展示了 Bazel 为每种浏览器生成独立测试目标:bazel test //py:unit(无浏览器单元测试)、bazel test //py:test-chrome(Chrome 浏览器测试)、bazel test //py:test-firefox(Firefox),单个测试文件的目标命名规则是test/<path>/<file>-<browser>[-variant],可用bazel query //py:all | grep <name>查全名。

5.3 Linux 上的有头测试:虚拟 X 服务器

Bazel 默认在当前 X 服务器 UI 上跑测试;没有显示器时可以用虚拟/嵌套 X 服务器:

  1. 启动 X 服务器:Xvfb :99Xnest :99

  2. 启动窗口管理器,例如:DISPLAY=:99 jwm

  3. 运行测试:

    bazel test --test_env=DISPLAY=:99 //java/... --test_tag_filters=chrome

更简单的方式是用 Bazel 的--run_under

bazel test --run_under="xvfb-run -a" //java/...

6. 文档与发布

6.1 API 文档生成

各语言绑定的 API 文档由./go <language>:docs更新,全部语言一次更新:

./go all:docs

对应 Rakefile 中all:docs任务会依次调用 java/py/rb/dotnet/node 五种语言绑定的 docs 任务(见 Rakefile)。

6.2 发布(Releasing)

发布是"构建 + 发布"的组合流程,往往需要多次执行并做额外处理。README 的核心要点:

  • 使用 Rake 任务(./go命令)完成构建与发布,且这些./go命令会附带--stamp参数,把版本等构建信息写入产物;这与 .bazelrc 中build:release --stamp--compilation_mode=opt的 release 配置相呼应。

  • 全量构建并发布:

    ./go all:release
  • 只发布指定语言:

    ./go <language>:release
  • 如果有 Selenium EngFlow 仓库的访问权限,可以远程构建资产并下载到本地:

    ./go all:release['--config', 'release']

    这种./go task['arg1', 'arg2']的括号语法由go脚本支持——它会把--之前的参数视为 Rake 任务参数、--之后视为 rake flags(见 go 脚本头部注释)。完整的发布流程步骤在官方 wiki 的 "Releasing Selenium" 页面。

7. 快速上手清单

结合 README 与仓库实际内容,一条最短的开发者上手路径是:

  1. 安装 Bazelisk 与 JDK 17+(设置好JAVA_HOME,用javac验证);
  2. 在目标目录克隆仓库;macOS 执行xcode-select --install,Windows 跑 scripts/dev-environment-setup.ps1 或按 2.3 节手动配置;
  3. 构建一个目标验证工具链:bazel build grid(日志中会给出 Grid jar 的输出位置);
  4. 跑一个小规模的单元测试确认环境闭环:bazel test //py:unitbazel test //java/... --test_size_filters=small
  5. 日常开发使用./go <language>:build/./go <language>:docs,格式化跑./scripts/format.sh
  6. 需要多 worktree 时,按 2.5 节配置用户级--disk_cache/--repository_cache与 per-worktree 的output_base

本文全部内容以当前仓库快照为准:Bazel 版本 9.1.0(.bazelversion)、JDK 17+ 环境要求、pin_browsers默认开启等细节均来自仓库文件本身,如后续仓库升级,请以仓库最新文档与配置为准。

【免费下载链接】seleniumA browser automation framework and ecosystem.项目地址: https://gitcode.com/GitHub_Trending/se/selenium

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询