Selenium诞生于2004年,以其开源、功能全面长期以来长期排名Web 自动化测试工具领域的Top1,是目前最主流的Web自动化测试工具,而Selenium的核心Webdriver 更是作为W3C的通行标准,被各类工具广泛参照。可以说是目前web自动化测试的事实标准。
Selenium 4带来的变化
Selenium本身经过多年的演进,目前已经发布到V4.24版本。 虽然目前网上还广泛流传V3版本相关的用法和资料,但Selenium 4 其实是一个非常大的更新版本。它的几个核心组件都进行的极大程度的重构。
- WebDriver 从原先的Json Wire Protocol 切换为了W3C的标准定义
- Selenium IDE 完成重构和功能优化
- Selenium Grid 完成重构,支持更灵活的云服务架构
此外Selenium 4中还引入了一个很重要的工具,也就是本篇我们要重点来介绍的Selenium Manager(实际是V4.6才引入,到V4.12 功能才基本完备
原先的浏览器驱动方式带来的问题
要了解Selenium Manager,我们还是要先了解下Selenium的工作原理。
Selenium工作原理
下图是官网给的Selenium本地运行的基本架构。
可以看到,Selenium实际上完成自动化,是通过webdriver协议驱动不同类型的浏览器(Chrome、Firefox、IE、Edge、Safari等)完成指定的动作,以此达到自动化执行的目的。
而驱动浏览器的关键,是和浏览器对应的浏览器Driver驱动,比如Chrome对应的ChromeDriver, FireFox对应的GecoDriver等。
而Selenium本身,则是基于WebDriver协议和浏览器Driver完成交互。
导致的问题
这个架构和工作原理虽然清晰,但是有一个问题,就是浏览器的版本是不断更新的。而浏览器驱动版本需要和浏览器版本匹配,不匹配的驱动和浏览器版本,共同工作可能存在各种预期外的异常,所以Selenium要正常工作,再用Selenium库完成编码前,首先就是要保证浏览器驱动和浏览器版本的部署和匹配。
但浏览器版本和对应的驱动,通常都是由浏览器厂商维护的。
所以这里的自动化测试环境准备就会变得比较复杂,要安装对应被测版本的浏览器,同时还要找到对应这个版本的驱动,再把相关路径配置给Selenium,然后Selenium才能完成正常的驱动。
此外,浏览器的版本,一般还有自动更新功能,可能在用户没感知的情况,其实版本已经变化了,但此时驱动版本并不会同步更新,所以也导致驱动和浏览器版本不匹配的潜在问题。
这个问题,其实长期没有得到很好地解决,Selenium 3和Selenium 4的早期版本,我们部署Selenium 自动化环境,浏览器版本和驱动版本的获取和匹配一直是一个比较麻烦的工作,也因此劝退了不少自动化测试小白。
Chrome对驱动问题的应对
既然这个问题由来已久,浏览器厂商其实也意识到驱动和浏览器版本不匹配,给自动化测试带来的困扰。
以Chrome为例,我们去到 ChromeDriver官方下载 网址的话,会看到这样的页面
可以看到,这里对Chrome Driver的下载只提供到了114版本,而最新的Chrome其实已经到了128版本。
对于115版本以后,Chrome浏览器其实调整了driver的发布策略,也就是Chrome driver会跟随 Chrome for Testing 版本同步发布。严格保证driver和浏览器版本的同步匹配。
那这里为什么有一个Chrome for Testing版本呢?
我们之前提到,浏览器版本,会有自动更新,如果进行自动更新,driver版本不会同步更新,所以导致dirver和浏览器的不匹配。
所以Chrome for Testing与正式版本的主要区别,其实就是 for Testing版本是不会进行自动更新的。
这样,再加上版本号和浏览器版本的共用,就能很方便地保证浏览器和驱动的一致。
Selenium应对驱动匹配问题的解决方案
那上面是浏览器对驱动匹配问题给出的解决方法,但其实还是没有完全解决浏览器、Driver需要分别获取和指定的问题。那么Selenium官方对这个问题的解决方案,就是Selenium Manager。它其实是一个包含在Selenium库中,无需额外安装的可执行程序。
我们目前使用Selenium V4来执行一个简单的自动化测试脚本的话:
比如通过百度,搜索城下秋草 测试
, 代码如下:
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
def test_baidu_search():
option = webdriver.ChromeOptions()
option.browser_version = '117'
driver = webdriver.Chrome(options=option)
driver.get("https://www.baidu.com")
driver.find_element(By.ID,'kw').send_keys('城下秋草 测试')
sleep(2)
driver.find_element(By.ID,'su').click()
sleep(3)
driver.close()
只要安装了Selenium库,执行的时候,就可以正常地驱动, 并不需要特别地去获取驱动和配置。
Selenium 4 启动自动化执行源码分析
这里我们从Selenium的Python源码来分析下它的启动过程:
driver = webdriver.Chrome(options=option)
这行代码其实会调用Slenium库中Chromium基础浏览器的webdriver初始化代码,位置在.venv/Lib/site-packages/selenium/webdriver/chromium/webdriver.py
初始化时,可以看到,会通过DriverFinder方法来获取浏览器和Driver的路径
finder = DriverFinder(self.service, options)
if finder.get_browser_path():
options.binary_location = finder.get_browser_path()
options.browser_version = None
self.service.path = finder.get_driver_path()
self.service.start()
而获取路径的方法,其实就是调用了SeleniumManager模块的binary_paths方法
def get_browser_path(self) -> str:
return self._binary_paths()["browser_path"]
def get_driver_path(self) -> str:
return self._binary_paths()["driver_path"]
def _binary_paths(self) -> dict:
if self._paths["driver_path"]:
return self._paths
.
.
.
output = SeleniumManager().binary_paths(self._to_args())
.
.
.
return self._paths
而SeleniumManager模块,则会执行SeleniumManager的二进制程序,根据相关参数,获取浏览器和驱动版本。
def _run(args: List[str]) -> dict:
"""Executes the Selenium Manager Binary.
:Args: - args: the components of the command being executed. :Returns: The log string containing the driver location. """ command = " ".join(args)
logger.debug("Executing process: %s", command)
try:
if sys.platform == "win32":
completed_proc = subprocess.run(args, capture_output=True, creationflags=subprocess.CREATE_NO_WINDOW)
else:
completed_proc = subprocess.run(args, capture_output=True)
stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
output = json.loads(stdout) if stdout != "" else {"logs": [], "result": {}}
except Exception as err:
raise WebDriverException(f"Unsuccessful command executed: {command}") from err
SeleniumManager._process_logs(output["logs"])
result = output["result"]
if completed_proc.returncode:
raise WebDriverException(
f"Unsuccessful command executed: {command}; code: {completed_proc.returncode}\n{result}\n{stderr}"
)
return result
所以,目前的Selenium 4版本执行时,会通过SeleniumManager程序来确定需要的浏览器和对应的driver版本。
Selenium Manager 命令行程序
而通过SeleniumManager,根据我们配置的浏览器类型和版本,它可以自动的匹配相关的driver版本,并自行联网,获取相关驱动和浏览器版本的文件,供Selenium调用。
比如上例中,我们指定了浏览器版本为 117
, 执行以后,在用户目录的 .cache\selenium
目录下其实就会保存下载的浏览器和对应的驱动版本。下图是当前执行更新的117 版本的驱动。
这里Selenium调用的是Selenium-manager这个命令行程序
我们可以直接执行这个程序,加上--help
看一下支持的参数
selenium-manager 0.4.24
Selenium Manager is a CLI tool that automatically manages the browser/driver infrastructure required by Selenium.
Usage: selenium-manager [OPTIONS]
Options:
--browser <BROWSER>
Browser name (chrome, firefox, edge, iexplorer, safari, safaritp, or webview2)
--driver <DRIVER>
Driver name (chromedriver, geckodriver, msedgedriver, IEDriverServer, or safaridriver)
--grid [<GRID_VERSION>]
Selenium Grid. If version is not provided, the latest version is downloaded
--driver-version <DRIVER_VERSION>
Driver version (e.g., 106.0.5249.61, 0.31.0, etc.)
--browser-version <BROWSER_VERSION>
Major browser version (e.g., 105, 106, etc. Also: beta, dev, canary -or nightly-, and esr -in Firefox- are accepted)
--browser-path <BROWSER_PATH>
Browser path (absolute) for browser version detection (e.g., /usr/bin/google-chrome, "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "C:\Program Files\Google\Chrome\Application\chrome.exe")
--driver-mirror-url <DRIVER_MIRROR_URL>
Mirror for driver repositories (e.g., https://registry.npmmirror.com/-/binary/chromedriver/)
--browser-mirror-url <BROWSER_MIRROR_URL>
Mirror for browser repositories
--output <OUTPUT>
Output type: LOGGER (using INFO, WARN, etc.), JSON (custom JSON notation), SHELL (Unix-like), or MIXED (INFO, WARN, DEBUG, etc. to stderr and minimal JSON to stdout) [default: LOGGER]
--os <OS>
Operating system (i.e., windows, linux, or macos)
--arch <ARCH>
System architecture (i.e., x32, x64, or arm64)
--proxy <PROXY>
HTTP proxy for network connection (e.g., https://myproxy.net:8080)
--timeout <TIMEOUT>
Timeout for network requests (in seconds) [default: 300]
--ttl <TTL>
TTL (time-to-live) for discovered versions (online) of drivers and browsers [default: 3600]
--cache-path <CACHE_PATH>
Local folder used to store downloaded assets (drivers and browsers), local metadata, and configuration file [default: ~/.cache/selenium]
--clear-cache
Clear cache folder (~/.cache/selenium)
--clear-metadata
Clear metadata file (~/.cache/selenium/selenium-manager.json)
--debug
Display DEBUG messages
--trace
Display TRACE messages
--log-level <LOG_LEVEL>
Level for output messages. The possible values are: info, debug, trace, warn, error
--offline
Offline mode (i.e., disabling network requests and downloads)
--force-browser-download
Force to download browser (even when browser is already in the system)
--avoid-browser-download
Avoid to download browser (even when browser-version is specified)
--language-binding <LANGUAGE_BINDING>
Selenium language bindings that invokes Selenium Manager (e.g., Java, JavaScript, Python, DotNet, Ruby)
--avoid-stats
Avoid sends usage statistics to plausible.io
-h, --help
Print help
-V, --version
Print version
我们可以执行看一下这里输出信息,其实selenium在执行时就是调用的这个命令行程序
>selenium-manager.exe --browser firefox --debug #debug参数显示详细输出
[2024-09-10T13:35:56.007Z DEBUG] geckodriver not found in PATH
# 首先在系统Path路径中根据指定的浏览器判断是否存在驱动
[2024-09-10T13:35:56.010Z DEBUG] firefox not found in PATH
# 同样根据Path路径中是否包含firefox浏览器安装路径
[2024-09-10T13:35:56.010Z DEBUG] Running command: REG QUERY HKCU\Software\Mozilla\Mozilla Firefox /v CurrentVersion
[2024-09-10T13:35:56.034Z DEBUG] Output: ""
[2024-09-10T13:35:56.036Z DEBUG] firefox not found in the system
# 通过注册表查找firefox浏览器安装路径
[2024-09-10T13:35:56.037Z DEBUG] Required browser: firefox 130.0
-- 未指定浏览器版本,根据联网信息获取最新版本
[2024-09-10T13:35:56.037Z DEBUG] Downloading firefox 130.0 from https://ftp.mozilla.org/pub/firefox/releases/130.0/win64/en-US/Firefox%20Setup%20130.0.exe
# 从官网下载
[2024-09-10T13:36:13.320Z DEBUG] firefox 130.0 is available at C:\Users\Administrator\.cache\selenium\firefox\win64\130.0\firefox.exe
# 完成下载
[2024-09-10T13:36:14.367Z DEBUG] Valid geckodriver versions for firefox 130: ["0.35.0", "0.34.0"]
# 获取可用driver 版本
[2024-09-10T13:36:14.369Z DEBUG] Required driver: geckodriver 0.35.0
[2024-09-10T13:36:14.372Z DEBUG] Downloading geckodriver 0.35.0 from https://github.com/mozilla/geckodriver/releases/download/v0.35.0/geckodriver-v0.35.0-win64.zip
# 下载对应driver
[2024-09-10T13:36:18.238Z INFO ] Driver path: C:\Users\Administrator\.cache\selenium\geckodriver\win64\0.35.0\geckodriver.exe
[2024-09-10T13:36:18.239Z INFO ] Browser path: C:\Users\Administrator\.cache\selenium\firefox\win64\130.0\firefox.exe
# 输出browser和driver路径,其实selenium调用时的返回值就是这个信息
而除了Browser和Driver外,Selenium-manager其实还支持grid版本的下载。通过--grid
参数就可以直接下载grid的最新版本。
> selenium-manager.exe --grid --debug
[2024-09-10T13:47:41.793Z DEBUG] Sending stats to Plausible: Props { browser: "grid", browser_version: "", os: "windows", arch: "amd64", lang: "", selenium_version: "4.24" }
[2024-09-10T13:47:41.795Z DEBUG] grid not found in the system
[2024-09-10T13:47:43.667Z DEBUG] Required driver: selenium-server 4.24.0
[2024-09-10T13:47:43.669Z DEBUG] Downloading selenium-server 4.24.0 from https://github.com/SeleniumHQ/selenium/releases/download/selenium-4.24.0/selenium-server-4.24.0.jar
[2024-09-10T13:47:51.547Z INFO ] Driver path: C:\Users\Administrator\.cache\selenium\grid\4.24.0\selenium-server-4.24.0.jar
通过以上介绍,可以看出,通过引入Selenium-manager,Selenium在环境准备时已经可以非常灵活地实现对浏览器、驱动包括grid server等资源的自动获取和配置,极大提升了使用Selenium的便利性。
更多测试职业进阶知识全方位梳理,可以关注我的新课
❤️ ❤️ ❤️ 测试高级工程师系统养成-高薪就业课 ❤️ ❤️ ❤️