Selenium 版本演进全解析:从 RC 到 WebDriver 4.0 的技术变迁

作为开发者和测试工程师,我们每天都在与自动化测试工具打交道。而在浏览器自动化领域,Selenium 无疑是那颗最耀眼的明星。你是否曾想过,为什么我们现在直接调用浏览器驱动,而十年前却需要启动一个中间服务器?这一切都源于 Selenium 过去二十年间的技术演进。

在这篇文章中,我们将一起回顾 Selenium 的进化史。我们不仅要了解“有哪些版本”,更要深入探究每一代版本背后的技术原理、核心架构变化,以及这些变化如何影响我们今天的代码编写方式。让我们开始这段穿越时光的技术之旅吧。

Selenium 版本演进概览

Selenium 的历史是一部对抗浏览器复杂性、追求测试稳定性与效率的历史。从最初的 JavaScript 注入技术到现在的 W3C 标准化协议,每一次大版本的更新都标志着技术的重大飞跃。

以下是 Selenium 主要版本的快速回顾:

  • Selenium 1 (Selenium RC): 发布于 2006 年,开创了自动化测试的先河,引入了“代理服务器”模式。
  • Selenium 2 (Selenium WebDriver): 发布于 2011 年,革命性地引入了原生驱动,直接与浏览器交互,淘汰了 RC 的服务器模式。
  • Selenium 3: 发布于 2016 年,专注于稳定性与标准化,彻底移除了 RC,并引入了更严谨的 API。
  • Selenium 4: 发布于 2021 年至今,全面拥抱 W3C 标准,集成了 Chrome DevTools 协议,带来了更强大的调试和测试能力。

Selenium 1 (Selenium RC):自动化测试的黎明

Selenium Remote Control (RC) 是 Selenium 项目的第一个主要版本。在那个年代,浏览器的安全策略非常严格,特别是“同源策略”,它阻止了一个域名的网页去访问另一个域名的数据。为了绕过这个限制,Selenium RC 创造性地设计了一个代理服务器机制。

工作原理:那个时代的“黑科技”

Selenium RC 的工作流程在今天看起来略显繁琐,但在当时却是天才般的设计:

  • 启动服务器:我们在运行测试前,必须手动启动一个 Java 编写的 Selenium RC 服务器。
  • 注入代理:这个服务器充当了浏览器和被测应用之间的“中间人”。
  • JavaScript 注入:当测试脚本发送指令(如“点击按钮”)时,RC 服务器会将 JavaScript 代码注入到当前浏览器页面中。
  • 执行与回调:注入的 JS 代码在浏览器上下文中执行操作,并将结果返回给 RC 服务器,服务器再反馈给我们的测试脚本。

代码示例:回顾 RC 风格的代码

虽然现在我们很少使用 RC,但了解它的语法有助于我们理解技术演进。以下是 RC 时代的典型代码风格(使用 Java 客户端):

// 在 Selenium 1 (RC) 时代,我们需要先启动一个服务器
// 然后实例化一个 DefaultSelenium 对象

import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;

public class RCTestExample {
    public static void main(String[] args) {
        // 1. 定义服务器地址、端口、浏览器类型和被测URL
        // 注意:*firefox 是 RC 时代特有的浏览器命令模式
        Selenium selenium = new DefaultSelenium("localhost", 4444, "*firefox", "http://www.example.com");
        
        try {
            // 2. 必须显式启动会话
            selenium.start();
            
            // 3. 打开页面
            selenium.open("/");
            
            // 4. 输入文本 - RC 使用类似自然语言的命令
            selenium.type("name=q", "Selenium RC");
            
            // 5. 点击按钮
            selenium.click("name=btnG");
            
            // 6. 等待页面加载 - RC 没有智能等待,通常需要手动暂停
            selenium.waitForPageToLoad("30000");
            
            // 7. 验证结果
            System.out.println("Page title is: " + selenium.getTitle());
            
        } finally {
            // 8. 关闭浏览器会话
            selenium.stop();
        }
    }
}

局限性与痛点

在实际使用中,我们很快发现了 Selenium RC 的瓶颈:

  • 速度慢:每次指令都要经过服务器转发和 JS 注入,交互极其笨重。
  • JavaScript 沙箱限制:由于依赖 JS 注入,它无法操作某些非标准的浏览器弹窗或上传文件等原生控件。
  • 繁琐的设置:每次测试前必须确保服务器启动,这让持续集成(CI)变得复杂。

尽管如此,Selenium RC 为跨浏览器自动化奠定了坚实的基础,它证明了 Web 自动化的可行性。

Selenium 2 (Selenium WebDriver):原生交互的革命

2011 年,Selenium 2 的横空出世彻底改变了游戏规则。这一版本的核心就是 WebDriver。WebDriver 不再依赖 JavaScript 注入,而是利用浏览器原生的 API 来进行控制。

架构升级:砍掉中间商

如果说 Selenium RC 是“隔靴搔痒”,那么 WebDriver 就是“直达病灶”。它直接调用浏览器的底层驱动(如 Chrome 的 chromedriver,Firefox 的 geckodriver)。这意味着:

  • 更快的速度:指令直接到达浏览器,无需中间服务器转发。
  • 更强的控制力:我们可以模拟真实的键盘输入、处理文件上传、操作浏览器原生弹窗,甚至绕过 JS 沙箱限制。

代码示例:WebDriver 的诞生

让我们看看 Selenium 2 时代的代码发生了什么变化。这种风格你可能非常熟悉,因为它奠定了我们今天编写测试的基础:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

public class WebDriverExample {
    public static void main(String[] args) {
        // 1. 直接实例化驱动,无需启动服务器
        // 在 Selenium 2 早期,Firefox 是内置支持的,无需额外下载 driver
        WebDriver driver = new FirefoxDriver();

        try {
            // 2. 导航到页面
            driver.get("http://www.example.com");

            // 3. 定位元素 - 使用更现代的定位策略
            WebElement searchBox = driver.findElement(By.name("q"));
            
            // 4. 模拟用户输入 - SendKeys 更加模拟真实键盘行为
            searchBox.sendKeys("Selenium WebDriver");
            
            // 5. 点击搜索按钮
            searchBox.submit();

            // 6. 获取页面标题进行断言
            System.out.println("Title: " + driver.getTitle());

        } finally {
            // 7. 关闭浏览器
            driver.quit();
        }
    }
}

代码解析:为什么 WebDriver 更好?

请注意上面的代码,我们使用了 INLINECODEfa0c453e。在 Selenium 2 中,定位元素的逻辑更加面向对象。我们不再传递字符串命令,而是操作 WebElement 对象。更重要的是,INLINECODE8920936f 是一个阻塞操作(在某些情况下),浏览器未加载完成前,控制权不会返回,这比 RC 的 waitForPageToLoad 更加智能。

Selenium 2 实际上是 Selenium RC 和 WebDriver 的合并体,在这个版本中,WebDriver 成为了主角,而 RC 逐渐退居二线,最终在 Selenium 3 中被移除。

Selenium 3:稳健与标准化

到了 2016 年,Web 变得更加复杂,前端框架如 React、Vue 开始流行。Selenium 3 的发布重点不在于增加花哨的新功能,而在于“瘦身”和“稳固”

核心变化:彻底告别 RC

在 Selenium 3 中,开发团队痛下决心,彻底移除了 Selenium RC 的原始代码。这意味着如果你维护着老项目,直接升级到 Selenium 3 会导致所有 RC 相关的代码报错。这是强制用户迁移到 WebDriver API 的一步。

另一个关键变化:自带驱动器的终结

在 Selenium 2 时代,Firefox 浏览器的驱动是内置在 Selenium Jar 包中的。但从 Selenium 3 开始,所有浏览器驱动都必须由用户单独下载并配置(通过 webdriver.gecko.driver 等系统属性)。这虽然增加了配置的繁琐度,但也让 Selenium 更加轻量,且能更快响应浏览器的版本更新。

实战配置:Selenium 3 的初始化

让我们看看在 Selenium 3 中,我们必须如何严谨地配置驱动路径(以 Chrome 为例):

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class Selenium3Setup {
    public static void main(String[] args) {
        // 1. 必须设置驱动路径,否则会抛出 IllegalStateException
        // 这是 Selenium 3 相比 2 最大的麻烦之一,但也更规范
        System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
        
        // 2. 使用 ChromeOptions 处理参数
        // Selenium 3 时代开始强调 Options 的使用
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--start-maximized");
        options.addArguments("--disable-infobars");
        
        WebDriver driver = new ChromeDriver(options);
        
        try {
            driver.get("https://www.example.com");
            // 测试逻辑...
        } finally {
            driver.quit();
        }
    }
}

Selenium 4:现代化与 W3C 标准

当我们来到 2021 年及以后,Selenium 4 成为了当下的主流。这也是目前我们最应该掌握的版本。它不仅仅是升级,而是对现代 Web 测试需求的彻底回应。

什么是 W3C WebDriver 标准?

在 Selenium 4 之前,Selenium 实现了一套自己的 WebDriver Wire Protocol(JSON Wire Protocol)。但在 Selenium 4 中,所有浏览器驱动(ChromeDriver, GeckoDriver 等)都统一遵循 W3C WebDriver 标准

这对我们意味着什么?

  • 更稳定的会话:浏览器和 Selenium 之间的通信更加标准化,减少了“Flaky Tests”(不稳定的测试)。
  • 更严格的类型:代码中的参数传递更加严格,许多隐式的类型转换不再生效。

相对定位器:像人一样查找元素

Selenium 4 引入了一个非常酷的功能:相对定位器。以前我们只能精确地找到一个元素,现在我们可以告诉 Selenium:“找到那个输入框上面的文本”。这让测试脚本在面对稍微变动的 UI 时更加健壮。

让我们看一个具体的代码示例:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.locators.RelativeLocator;

import static org.openqa.selenium.support.locators.RelativeLocator.withTagName;

public class Selenium4RelativeLocators {
    public static void main(String[] args) {
        System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
        WebDriver driver = new ChromeDriver();
        
        try {
            driver.get("https://www.example.com/login");
            
            // 假设我们有一个密码输入框,我们知道它的 ID
            WebElement passwordField = driver.findElement(By.id("password"));
            
            // 现在,我们想要找到密码输入框上面的那个元素(通常是用户名输入框)
            // 使用 Selenium 4 新增的 withTagName 方法
            WebElement usernameField = driver.findElement(
                RelativeLocator.withTagName("input").above(passwordField)
            );
            
            usernameField.sendKeys("my_username");
            
            // 还可以使用 below(), toLeftOf(), toRightOf(), near()
            // 这种写法非常接近人类的思维方式
            
        } finally {
            driver.quit();
        }
    }
}

窗口管理:新标签页处理更简单

在 Selenium 3 中,处理新打开的标签页通常需要获取所有窗口句柄,然后进行切换。在 Selenium 4 中,虽然机制类似,但 API 变得更加清晰。更重要的是,Selenium 4 增强了对多窗口和尺寸调整的控制。

Chrome DevTools 协议 (CDP) 支持

这是 Selenium 4 的高级特性。现在我们可以直接通过 Selenium 访问 Chrome 的 DevTools 功能。这意味着我们可以:

  • 捕获网络流量:查看 API 请求和响应。
  • 模拟网络状况:测试网站在 3G 网络下的表现。
  • 控制加载速度:拦截请求,提高测试效率。

以下是一个使用 CDP 模拟慢速网络的示例,这对于测试性能加载非常有用:

import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v85.network.Network;
import org.openqa.selenium.devtools.v85.network.model.ConnectionType;
// 注意:DevTools 的包名版本可能会随具体 driver 版本变化,这里以 v85 示意

public class Selenium4DevTools {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        DevTools devTools = ((HasDevTools) driver).getDevTools();
        devTools.createSession();
        
        try {
            // 启用 Network 监听
            devTools.send(Network.enable());
            
            // 模拟网络速度:这里设置为下载 500KBps,上传 500KBps,延迟 20ms
            // 这在测试前端加载动画时非常有用
            devTools.send(Network.emulateNetworkConditions(
                false, // offline
                20,    // latency
                500,   // download throughput
                500,   // upload throughput
                ConnectionType.CELLULAR4G // connection type
            ));
            
            driver.get("https://www.example.com");
            // 你的测试代码...
            
        } finally {
            driver.quit();
        }
    }
}

结论:我们应该选择哪个版本?

回顾 Selenium 从 1 到 4 的演变,我们看到的是一条从“能做到”到“做得好”再到“做得专业”的清晰路径。

  • 如果你还在维护使用 Selenium RC 的代码,现在必须迁移了,Selenium 3 及以上版本已经完全不支持它。
  • 如果你还在使用 Selenium 2 (WebDriver),虽然代码能跑,但你会错过 Selenium 4 的 W3C 标准带来的稳定性以及强大的 CDP 功能。
  • 对于新项目,强烈建议直接使用 Selenium 4。它不仅修复了历史遗留的稳定性问题,还提供了像相对定位器、DevTools 集成等现代化手段,能让我们写出更健壮、更贴近真实用户体验的测试代码。

技术永远在向前发展,保持工具的更新换代,是我们每一位测试工程师应对日益复杂的 Web 应用的必经之路。希望这篇文章能帮你理清 Selenium 的版本脉络,更好地驾驭这个强大的工具。

常见问题解答

Selenium 1 (RC) 和 Selenium 2 (WebDriver) 有什么根本区别?

最核心的区别在于通信机制。Selenium 1 (RC) 需要一个中间服务器将指令转换为 JavaScript 注入浏览器,受限于同源策略且速度较慢。Selenium 2 (WebDriver) 直接使用浏览器的原生 API 进行通信,速度更快,且能绕过 JavaScript 的安全限制,操作更底层。

我可以从 Selenium 2 直接跳到 Selenium 4 吗?

是的,完全可以。Selenium 4 在很大程度上向后兼容 Selenium 3 的代码。但要注意,如果你使用的是非常老的 Selenium 2 代码(例如废弃的 By.name 的特定用法或某些未类型化的 API),可能需要进行微小的调整。同时,你需要确保浏览器驱动都是最新版本。

为什么我的 Selenium 4 代码启动浏览器这么慢?

这可能是因为你没有正确配置 Selenium Manager(Selenium 4 自带的管理工具),或者你没有正确引入 W3C 依赖。另外,检查是否开启了过多的 Chrome 选项(如 headless 模式配置不当)。通常 Selenium 4 的启动速度比旧版本更稳定,因为它标准化了握手过程。

Selenium 是免费的吗?我可以把它用在商业项目中吗?

是的,Selenium 是开源软件,遵循 Apache 2.0 许可证。这意味着它是完全免费的,你可以自由地使用、修改和分发它,无论是在个人项目还是大型商业项目中都是合法的。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/40198.html
点赞
0.00 平均评分 (0% 分数) - 0