3、Selenium基础入门:Selenium简介、WebDriver核心API、定位元素八大方法

好,咱们进入自动化测试的重头戏——Selenium。说实话,我刚开始接触自动化测试时,第一个接触的工具就是Selenium。那时候它还是个简单的录制回放工具,现在已经是Web自动化领域的标配了。这一章,我带大家把Selenium的底子打扎实。

3.1 Selenium是什么?

Selenium,说白了就是一个浏览器自动化工具集。它不是一个单一的工具,而是一套工具家族。我习惯把它分成三块:

  • Selenium WebDriver:核心中的核心,直接操控浏览器
  • Selenium IDE:录制回放工具,适合快速原型验证
  • Selenium Grid:分布式测试,多浏览器并行跑

咱们课程主要聚焦在WebDriver上。为什么?因为实际项目中,90%的自动化脚本都是用WebDriver写的。IDE适合入门演示,但真要上生产环境,还得靠WebDriver。

核心概念:WebDriver直接调用浏览器的原生API,模拟用户操作。它不是通过JavaScript注入来操控页面,所以更稳定、更接近真实用户行为。

3.2 WebDriver核心API

WebDriver的API设计得很直观。我给大家梳理一下最常用的几个操作:

3.2.1 启动浏览器

// 启动Chrome浏览器
WebDriver driver = new ChromeDriver();

// 启动Firefox浏览器
WebDriver driver = new FirefoxDriver();

// 启动Edge浏览器
WebDriver driver = new EdgeDriver();

嗯,这里要注意一点:不同浏览器需要对应的驱动文件。Chrome需要chromedriver,Firefox需要geckodriver。我曾经因为驱动版本不匹配,折腾了一下午才发现问题。

避坑指南:驱动版本必须和浏览器版本对应。比如Chrome 120版本,就要用120.x.x.x的chromedriver。去https://chromedriver.chromium.org/下载时,看清楚版本号。

3.2.2 页面导航

// 打开网页
driver.get("https://www.example.com");

// 返回上一页
driver.navigate().back();

// 前进到下一页
driver.navigate().forward();

// 刷新页面
driver.navigate().refresh();

我个人习惯用get()方法,简单直接。navigate()系列方法在需要模拟浏览器前进后退时特别有用。比如测试购物车流程时,我会用back()验证页面状态是否正确。

3.2.3 窗口管理

// 最大化窗口
driver.manage().window().maximize();

// 设置窗口大小
driver.manage().window().setSize(new Dimension(1024, 768));

// 获取当前窗口句柄
String currentHandle = driver.getWindowHandle();

// 获取所有窗口句柄
Set<String> allHandles = driver.getWindowHandles();

你想想看,为什么测试时要最大化窗口?因为有些元素在非最大化状态下可能被遮挡,导致定位失败。我在项目中遇到过好几次,脚本在本地跑得好好的,一到CI环境就报错,最后发现是窗口大小不一致导致的。

3.2.4 元素交互

// 点击元素
driver.findElement(By.id("submit-btn")).click();

// 输入文本
driver.findElement(By.name("username")).sendKeys("testuser");

// 清除文本
driver.findElement(By.id("search-box")).clear();

// 获取元素文本
String text = driver.findElement(By.className("title")).getText();

// 获取元素属性
String value = driver.findElement(By.tagName("input")).getAttribute("value");

小技巧sendKeys()方法可以模拟键盘操作。比如sendKeys(Keys.ENTER)可以模拟回车键,sendKeys(Keys.TAB)可以切换焦点。我在测试表单提交时经常用这个。

3.3 定位元素八大方法

定位元素是自动化测试的核心技能。说白了,你找不到元素,后面的操作都白搭。Selenium提供了八种定位方式,我按使用频率给大家排个序:

定位方法 语法示例 适用场景 推荐指数
ID定位 By.id("username") 元素有唯一ID时 ⭐⭐⭐⭐⭐
Name定位 By.name("email") 表单元素常用 ⭐⭐⭐⭐
ClassName定位 By.className("btn-primary") 样式类名唯一时 ⭐⭐⭐
TagName定位 By.tagName("input") 获取一组同类元素 ⭐⭐
LinkText定位 By.linkText("点击这里") 精确匹配超链接文本 ⭐⭐⭐
PartialLinkText定位 By.partialLinkText("点击") 模糊匹配超链接文本 ⭐⭐
CSS选择器定位 By.cssSelector("#login-form input[type='text']") 复杂定位场景 ⭐⭐⭐⭐⭐
XPath定位 By.xpath("//div[@class='container']//button") 最灵活,但性能稍差 ⭐⭐⭐⭐

3.3.1 ID定位——我的首选

为什么ID定位是首选?因为ID在HTML中应该是唯一的。我写脚本时,第一反应就是看元素有没有ID。有ID就用ID,没有才考虑其他方法。

// 找到登录按钮并点击
WebElement loginBtn = driver.findElement(By.id("login-button"));
loginBtn.click();

经验之谈:如果开发同学给元素加了动态ID(比如"btn_123456"这种),那就别用ID定位了。我遇到过前端框架自动生成随机ID的情况,这时候用CSS选择器或XPath更靠谱。

3.3.2 Name定位——表单的标配

表单元素通常都有name属性,因为提交表单时后端靠name来接收数据。所以定位输入框时,name定位很常用。

// 定位用户名输入框
WebElement usernameInput = driver.findElement(By.name("username"));
usernameInput.sendKeys("admin");

3.3.3 ClassName定位——小心重复

ClassName定位有个坑:class属性通常有多个值,比如class="btn btn-primary"。这时候用By.className("btn")只能匹配到第一个值。我建议用CSS选择器来定位带多个class的元素。

// 不推荐:可能匹配到多个元素
driver.findElement(By.className("btn"));

// 推荐:用CSS选择器精确定位
driver.findElement(By.cssSelector(".btn.btn-primary"));

3.3.4 TagName定位——批量操作的好手

TagName定位适合获取一组相同标签的元素。比如获取页面上所有的链接:

// 获取所有链接
List<WebElement> allLinks = driver.findElements(By.tagName("a"));
System.out.println("页面共有 " + allLinks.size() + " 个链接");

注意我用的是findElements(带s),返回的是列表。如果页面没有匹配的元素,它会返回空列表,不会抛异常。而findElement找不到元素会直接报NoSuchElementException

3.3.5 LinkText和PartialLinkText——链接专用

这两个方法专门用来定位超链接。LinkText要求完全匹配,PartialLinkText可以模糊匹配。

// 精确匹配
driver.findElement(By.linkText("关于我们")).click();

// 模糊匹配
driver.findElement(By.partialLinkText("关于")).click();

小技巧:如果页面上有多个链接包含"关于"两个字,PartialLinkText会返回第一个匹配到的。这时候可以用findElements获取所有匹配的链接,再根据索引或文本内容选择。

3.3.6 CSS选择器——我的最爱

CSS选择器是我个人最常用的定位方式。它语法简洁,定位能力强,性能也比XPath好。你想想看,前端开发写样式用的就是CSS选择器,我们拿来定位元素,天然匹配。

// 通过ID定位
By.cssSelector("#username");

// 通过class定位
By.cssSelector(".btn-primary");

// 通过属性定位
By.cssSelector("input[type='submit']");

// 层级定位
By.cssSelector("div.form-group > input");

// 组合定位
By.cssSelector("input#username.form-control");

3.3.7 XPath——万能但需谨慎

XPath是定位界的瑞士军刀,什么都能定位到。但它的缺点是语法相对复杂,而且性能不如CSS选择器。我建议:能用CSS选择器解决的问题,就别用XPath。

// 绝对路径(不推荐)
By.xpath("/html/body/div[1]/form/input[1]");

// 相对路径(推荐)
By.xpath("//input[@id='username']");

// 包含文本
By.xpath("//button[contains(text(), '提交')]");

// 多条件组合
By.xpath("//input[@type='text' and @name='username']");

避坑指南:绝对路径XPath非常脆弱,页面结构稍微一变就失效。我曾经接手过一个项目,里面全是绝对路径XPath,每次前端改版都要重写几十个定位。后来我全部改成了相对路径+属性组合,维护成本直线下降。

3.4 实战建议

说了这么多,我给大家总结几条实战中的经验:

  1. 优先用ID:有ID就用ID,没有ID就用CSS选择器
  2. 避免绝对路径:不管是XPath还是CSS,都不要写死层级
  3. 多用相对路径:从父元素往下找,比从根节点找稳定得多
  4. 组合定位更可靠:一个属性不够,就加两个属性
  5. 先手动验证:在浏览器控制台用$()$x()测试定位表达式,确认能定位到再写进代码

嗯,这一章的内容就到这里。定位元素是自动化测试的基本功,建议大家多练、多踩坑。下一章我们讲等待机制和浏览器操作,到时候会用到今天学的定位方法。