Selenium+Java自动化测试入门:从环境搭建到实战脚本编写
1. 项目概述
最近几年,自动化测试已经从一个“锦上添花”的技能,变成了很多测试和开发岗位的硬性要求。特别是对于Web应用,Selenium几乎是绕不开的名字。但很多刚接触的朋友,一上来就被“环境搭建”、“元素定位”、“脚本编写”这些词给唬住了,感觉门槛很高。其实,只要你有一点点Java基础,跟着清晰的步骤走,从零开始到写出第一个能跑的自动化脚本,可能只需要一个下午。这篇文章,我就想和你分享我这些年用Selenium+Java做自动化测试的实战经验,从最头疼的环境搭建开始,到最核心的元素操作,手把手带你走一遍。无论你是想转行做测试,还是开发想提升自己的测试能力,这篇内容都能给你一个扎实的起点。
2. 环境搭建:从零开始的“破冰”之旅
环境搭建是劝退新手的第一个拦路虎。网上教程很多,但版本对不上、依赖冲突、路径问题,随便一个都能卡半天。我总结了一套最稳定、最不容易出错的流程,帮你一次搞定。
2.1 核心工具选型与安装
首先,我们需要明确技术栈: Java + Selenium WebDriver + 浏览器驱动 + 构建工具 。别被吓到,我们一个个来。
-
Java环境 (JDK) :这是基础。建议直接安装 JDK 8 或 JDK 11 的LTS(长期支持)版本。这两个版本在企业中应用最广,兼容性也最好。去Oracle官网或者Adoptium(原AdoptOpenJDK)下载安装包,安装后记得配置
JAVA_HOME环境变量,并把%JAVA_HOME%\bin添加到系统的PATH变量里。验证方法是在命令行输入java -version,能看到版本信息就对了。 -
构建与管理工具 (Maven) :强烈推荐使用Maven来管理项目依赖。它就像个“大管家”,你只需要在配置文件里声明需要什么库(比如Selenium),它就会自动帮你下载,并且处理好库与库之间的依赖关系,省心省力。去Apache官网下载Maven,解压后同样需要配置
MAVEN_HOME和PATH。验证命令是mvn -v。 -
集成开发环境 (IDE) : IntelliJ IDEA (社区版免费)或 Eclipse 任选其一。IDEA对Java和Maven的支持更智能,我个人更推荐。用IDE能极大提升编码和调试效率。
2.2 创建Maven项目与引入Selenium
打开你的IDE(以IDEA为例),选择新建一个Maven项目。项目创建成功后,找到根目录下的 pom.xml 文件,这是Maven的“购物清单”。我们需要在里面添加Selenium的依赖。
在 <dependencies> 标签内,添加如下依赖配置:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.15.0</version> <!-- 使用当前稳定版本 -->
</dependency>
保存 pom.xml 文件后,IDEA通常会提示你导入更改(Enable Auto-Import),点击确认。Maven就会自动从中央仓库下载Selenium库及其所有依赖项到你的本地仓库。这个过程是自动的,你只需要等待右下角的进度条走完。
注意 :版本号建议使用官方发布的最新稳定版。直接写
<version>4.15.0</version>比写<version>LATEST</version>更稳妥,能避免因版本自动升级带来的意外问题。
2.3 下载与配置浏览器驱动
这是最关键也最容易出错的一步。Selenium WebDriver本身不能直接控制浏览器,它需要通过一个叫“浏览器驱动”的中间件来发号施令。
-
下载驱动 :
- Chrome驱动 (ChromeDriver) :去 ChromeDriver官网 下载。 版本必须与你电脑上安装的Chrome浏览器大版本号完全匹配 。比如你Chrome是120.x.x版本,就下载120.x.x.x版本的ChromeDriver。
- Firefox驱动 (GeckoDriver) :去 GitHub Mozilla仓库 下载对应你操作系统的版本。
-
配置驱动路径 :有三种常用方法,推荐第一种,最简单。
- 方法一:放入系统PATH 。将下载好的驱动文件(如
chromedriver.exe或geckodriver)直接放在一个目录下(例如C:\WebDriver),然后将这个目录路径添加到系统的PATH环境变量中。这是最一劳永逸的方法,所有项目都能用。 - 方法二:在代码中指定路径 。在创建WebDriver对象时,通过
System.setProperty来指定。System.setProperty("webdriver.chrome.driver", "C:/WebDriver/chromedriver.exe"); WebDriver driver = new ChromeDriver(); - 方法三:使用WebDriverManager(强烈推荐) 。这是一个第三方库,能自动帮你下载、匹配和管理浏览器驱动,彻底告别手动下载和版本匹配的烦恼。在
pom.xml中添加依赖:
然后在代码中,创建驱动前调用一行即可:<dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>5.6.2</version> </dependency>WebDriverManager.chromedriver().setup(); WebDriver driver = new ChromeDriver();
- 方法一:放入系统PATH 。将下载好的驱动文件(如
实操心得 :新手强烈推荐使用 WebDriverManager 。它极大降低了环境配置的复杂度,让你能更专注于学习Selenium API本身。我团队的新人培训,第一步就是教他们用这个。
3. 第一个自动化脚本:让浏览器动起来
环境配好了,我们来写第一个脚本,目标是打开百度,搜索一个关键词。别小看这个简单的脚本,它包含了自动化测试最核心的流程:启动浏览器 -> 导航到URL -> 定位元素 -> 交互操作 -> 验证结果 -> 关闭浏览器。
3.1 脚本结构与核心API
创建一个Java类,比如叫 FirstSeleniumTest 。
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
public class FirstSeleniumTest {
public static void main(String[] args) {
// 1. 自动设置浏览器驱动(使用WebDriverManager)
WebDriverManager.chromedriver().setup();
// 2. 实例化WebDriver对象,启动Chrome浏览器
WebDriver driver = new ChromeDriver();
try {
// 3. 导航到目标网址
driver.get("https://www.baidu.com");
// 等待页面加载(简单处理,生产环境应用显式等待)
Thread.sleep(2000);
// 4. 定位搜索框元素
WebElement searchBox = driver.findElement(By.id("kw"));
// 5. 在搜索框中输入文本
searchBox.sendKeys("Selenium自动化测试");
// 6. 定位“百度一下”按钮并点击
WebElement searchButton = driver.findElement(By.id("su"));
searchButton.click();
// 等待搜索结果加载
Thread.sleep(3000);
// 7. 简单的断言:验证页面标题是否包含搜索词
String pageTitle = driver.getTitle();
if (pageTitle.contains("Selenium自动化测试")) {
System.out.println("测试通过!页面标题包含搜索词。");
} else {
System.out.println("测试失败!页面标题为:" + pageTitle);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 8. 关闭浏览器
driver.quit();
}
}
}
代码逐行解析 :
WebDriverManager.chromedriver().setup();: 自动处理ChromeDriver的下载和路径设置。WebDriver driver = new ChromeDriver();: 创建驱动对象,这行代码执行时会弹出一个全新的、干净的Chrome浏览器窗口。driver.get(url): 命令浏览器加载指定URL。driver.findElement(By.id("kw")): 核心操作 。通过元素的id属性来定位页面上的搜索框。By.id是众多定位方式中最快、最稳定的一种。sendKeys(“text”): 向定位到的输入框模拟键盘输入。click(): 模拟鼠标点击操作。driver.getTitle(): 获取当前浏览器页签的标题。driver.quit(): 非常重要 !关闭浏览器并释放WebDriver会话占用的所有资源。务必在finally块或测试结束后调用,否则会导致后台进程残留。
3.2 运行与调试
在IDEA中,直接右键点击类文件,选择 Run ‘FirstSeleniumTest.main()‘ 。你会看到Chrome浏览器自动打开,访问百度,输入文字,点击搜索,最后关闭。控制台会打印出断言结果。
常见问题1:浏览器闪退,脚本报错
NoSuchSessionException或InvalidSessionIdException这通常是因为浏览器驱动版本与浏览器版本不匹配,或者浏览器正在自动更新。 解决方案 :确认版本匹配,或者使用WebDriverManager。如果还不行,尝试在启动浏览器时添加参数禁用自动更新:ChromeOptions options = new ChromeOptions(); options.addArguments(“–disable-browser-side-navigation”); WebDriver driver = new ChromeDriver(options);
常见问题2:
findElement报错NoSuchElementException这是自动化测试中最常见的错误,意思是“没找到这个元素”。原因有三:1)页面还没加载完你就去找元素了;2)你写的定位器(如By.id(“kw”))不对;3)元素在iframe或shadow DOM里。 解决方案 :对于原因1,需要使用“等待”策略,下文会讲。对于原因2,需要借助浏览器开发者工具(F12)仔细核对元素的属性。
4. 元素定位:自动化测试的“眼睛”
如果说WebDriver是自动化测试的“手”和“脚”,那么元素定位就是它的“眼睛”。找不到元素,一切操作都无从谈起。Selenium提供了8种主要的定位方式,我把它们分为“首选”、“备用”和“最后手段”三类。
4.1 首选定位策略(稳定、高效)
-
By.id :通过HTML元素的
id属性定位。id在理想情况下应该是页面内唯一的,所以定位最快、最准。driver.findElement(By.id(“username”)); -
By.name :通过
name属性定位。常用于表单元素,如输入框、单选按钮。driver.findElement(By.name(“password”)); -
By.linkText / By.partialLinkText :通过超链接的完整文本或部分文本定位。专门用于
<a>标签。driver.findElement(By.linkText(“忘记密码?”)); driver.findElement(By.partialLinkText(“忘记”)); // 匹配包含“忘记”的链接
4.2 备用定位策略(灵活、常用)
当 id 和 name 不可用时,CSS选择器和XPath是主力。
-
By.cssSelector :使用CSS选择器语法定位。语法强大,性能优于XPath,是WebDriver官方推荐的首选复杂定位方式。
// 通过class定位 driver.findElement(By.cssSelector(“.submit-btn”)); // 通过属性定位 driver.findElement(By.cssSelector(“input[type=’email’]”)); // 父子层级定位 driver.findElement(By.cssSelector(“div#container > form > input.username”)); -
By.xpath :使用XML路径语言定位。功能最强大,可以遍历整个DOM树,但写起来复杂,执行速度相对较慢。 慎用绝对路径(以
/开头) ,因为它极度脆弱,页面结构微调就会失效。// 相对路径,通过属性定位 driver.findElement(By.xpath(“//input[@name=’q’]”)); // 使用文本内容定位 driver.findElement(By.xpath(“//button[text()=’登录’]”)); // 使用包含函数 driver.findElement(By.xpath(“//a[contains(@href, ‘logout’)]”));
4.3 其他定位方式
-
By.className :通过
class属性定位。注意,一个元素可能有多个class,这里需要填写完整的class名称(空格分隔的其中一个)。driver.findElement(By.className(“btn-primary”)); -
By.tagName :通过标签名定位,如
<div>,<input>。通常返回多个元素,需用findElements。List<WebElement> inputs = driver.findElements(By.tagName(“input”)); -
By.className 的变体:实际上,
By.cssSelector(“.myClass”)比By.className(“myClass”)更常用,因为CSS选择器功能更全面。
定位策略黄金法则 :
- 优先级 :
id>name>cssSelector>xpath> 其他。 - 唯一性 :确保你的定位器在当前页面能唯一标识目标元素。在开发者工具中使用
Ctrl+F(或Cmd+F)在Elements面板测试你的定位器,看是否只高亮一个元素。 - 可读性与维护性 :尽量使用有业务意义的属性(如
id=“loginButton”)来定位。避免使用长的、嵌套很深的XPath或CSS,它们很难维护。
实操心得 :对于现代前端框架(如React, Vue)构建的单页应用,元素 id 可能动态生成或根本没有。这时, 与开发团队约定一套用于测试的定位属性 是最高效的做法。例如,让开发同学为关键元素添加固定的 data-testid 属性(如 data-testid=”login-submit” ),然后你就可以用 By.cssSelector(“[data-testid=’login-submit’]”) 来稳定定位,完全不受UI样式或结构微调的影响。
5. 等待机制:让脚本“聪明”地等待
页面加载需要时间,元素出现有快有慢。如果脚本在元素出现前就去操作它,就会抛出 NoSuchElementException 。因此,“等待”是编写健壮自动化脚本的关键。
5.1 三种等待方式
-
硬性等待 (Thread.sleep) :上面示例中用的
Thread.sleep(3000)就是。它让线程暂停指定的毫秒数。 这是最不推荐的方式 ,因为它不管页面是否 ready,都死等。时间设短了会失败,设长了浪费执行时间。 -
隐式等待 (Implicit Wait) :通过
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10))设置。它告诉WebDriver在查找 任何 元素时,如果没立即找到,就轮询等待一段时间(最多10秒)。这是一个全局设置,只需要设置一次。- 优点 :写法简单。
- 缺点 :不够灵活,会影响所有
findElement操作。如果元素真的不存在,你还是得等满10秒才会报错。
-
显式等待 (Explicit Wait) : 这是生产环境推荐的最佳实践 。它为某个特定条件(如“元素可点击”、“元素可见”)设置一个最大等待时间,并在这个时间内不断检查条件是否满足。使用
WebDriverWait类配合ExpectedConditions。// 引入相关类 import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.ExpectedConditions; import java.time.Duration; // 创建WebDriverWait对象,设置最大等待时间10秒 WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // 等待直到“百度一下”按钮可被点击 WebElement searchBtn = wait.until(ExpectedConditions.elementToBeClickable(By.id(“su”))); searchBtn.click(); // 等待直到页面标题包含特定文字 wait.until(ExpectedConditions.titleContains(“Selenium”));
5.2 显式等待的常用条件
ExpectedConditions 提供了大量预定义条件:
presenceOfElementLocated(By locator):元素出现在DOM中(不一定可见)。visibilityOfElementLocated(By locator):元素可见(宽高大于0)。elementToBeClickable(By locator):元素可见且可点击。textToBePresentInElement(By locator, String text):元素文本包含特定文字。alertIsPresent():出现alert弹窗。
为什么显式等待最好? 因为它将等待逻辑与具体操作绑定,更符合“等到某个事情发生再继续”的真实场景。它只在需要的时候等待,且一旦条件满足就立刻继续,效率最高,脚本也最健壮。
避坑技巧 :在实际项目中,我通常会封装一个通用的等待方法,并设置一个合理的超时时间(如10-15秒)和轮询间隔(默认0.5秒)。对于特别慢的网络或操作,可以单独为某个步骤设置更长的等待。
6. 常见的元素操作与高级交互
定位到元素后,我们就可以与之交互了。除了最基本的 click() 和 sendKeys() ,还有很多常用操作。
6.1 基础操作
- 点击与输入 :前面已经演示过。
- 清除内容 :
element.clear(),用于清空输入框。 - 获取文本/属性 :
String text = element.getText(); // 获取元素显示的文本 String value = element.getAttribute(“value”); // 获取属性值,如input的value String href = element.getAttribute(“href”); // 获取链接地址 - 判断状态 :
boolean isDisplayed = element.isDisplayed(); // 是否可见 boolean isEnabled = element.isEnabled(); // 是否可用(非disabled) boolean isSelected = element.isSelected(); // 是否被选中(用于复选框、单选框)
6.2 处理下拉框 (Select)
对于HTML的 <select> 标签,Selenium提供了专门的 Select 类,非常方便。
import org.openqa.selenium.support.ui.Select;
WebElement dropdown = driver.findElement(By.id(“country”));
Select select = new Select(dropdown);
// 1. 通过可见文本选择
select.selectByVisibleText(“中国”);
// 2. 通过value属性选择
select.selectByValue(“CN”);
// 3. 通过索引选择(从0开始)
select.selectByIndex(1);
// 获取所有选项
List<WebElement> allOptions = select.getOptions();
// 获取已选中的选项
WebElement selectedOption = select.getFirstSelectedOption();
6.3 处理弹窗 (Alert)
当页面出现JavaScript的 alert , confirm , prompt 弹窗时,需要先切换到弹窗才能操作。
// 等待弹窗出现(使用显式等待)
wait.until(ExpectedConditions.alertIsPresent());
// 切换到弹窗
Alert alert = driver.switchTo().alert();
// 获取弹窗文本
String alertText = alert.getText();
System.out.println(“弹窗信息:” + alertText);
// 点击“确定”
alert.accept();
// 或者点击“取消”
// alert.dismiss();
// 如果是prompt,还可以输入文字
// alert.sendKeys(“输入内容”);
6.4 模拟键盘与鼠标高级操作
对于更复杂的交互,如悬停、双击、拖拽等,需要使用 Actions 类。
import org.openqa.selenium.interactions.Actions;
Actions actions = new Actions(driver);
WebElement menu = driver.findElement(By.id(“menu”));
// 鼠标悬停
actions.moveToElement(menu).perform();
// 右键点击
actions.contextClick(menu).perform();
// 双击
actions.doubleClick(menu).perform();
// 拖拽元素A到元素B
WebElement source = driver.findElement(By.id(“draggable”));
WebElement target = driver.findElement(By.id(“droppable”));
actions.dragAndDrop(source, target).perform();
注意事项 : Actions 类的操作链必须以 .perform() 结束才会执行。对于复杂的组合操作(如按住Ctrl键点击多个元素),可以使用 keyDown , keyUp , clickAndHold , release 等方法进行构建。
7. 实战:编写一个完整的测试用例
让我们把上面的知识点串起来,写一个稍微复杂点的例子:测试一个登录流程。
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import io.github.bonigarcia.wdm.WebDriverManager;
import java.time.Duration;
public class LoginTest {
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
try {
// 1. 打开登录页
driver.get(“https://example.com/login”);
driver.manage().window().maximize(); // 最大化窗口
// 2. 输入用户名(使用显式等待确保元素加载)
WebElement usernameField = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id(“username”))
);
usernameField.clear();
usernameField.sendKeys(“testuser”);
// 3. 输入密码
WebElement passwordField = driver.findElement(By.id(“password”));
passwordField.sendKeys(“securepassword123”);
// 4. 点击登录按钮
WebElement loginButton = driver.findElement(By.cssSelector(“button[type=’submit’]”));
loginButton.click();
// 5. 验证登录成功(例如,页面跳转后出现用户头像)
// 等待跳转完成,可以通过URL变化或新页面元素出现来判断
wait.until(ExpectedConditions.urlContains(“/dashboard”));
WebElement userAvatar = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.className(“user-avatar”))
);
// 6. 断言:头像是否显示
if (userAvatar.isDisplayed()) {
System.out.println(“登录成功测试通过!”);
} else {
System.out.println(“登录成功测试失败:未找到用户头像。”);
}
// 7. (可选)测试登录失败场景
// 可以导航回登录页,输入错误密码,验证错误提示信息是否出现
} catch (TimeoutException e) {
System.err.println(“元素定位超时:” + e.getMessage());
// 这里可以截图,方便排查问题
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// 将screenshot文件保存到指定位置...
} catch (Exception e) {
System.err.println(“测试执行过程中发生异常:” + e.getMessage());
e.printStackTrace();
} finally {
// 8. 等待几秒便于观察,然后退出
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.quit();
}
}
}
这个例子涵盖了:环境启动、显式等待、多种元素定位、基础操作、成功/失败验证以及简单的异常处理。 一个关键点是第5步的验证 ,我们通过等待URL变化和新元素出现,来确认登录这个“动作”确实成功了,这是一种更可靠的断言方式。
8. 常见问题排查与调试技巧
即使按照最佳实践编写脚本,也难免会遇到问题。以下是几个“保命”的调试技巧。
8.1 问题排查清单
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
NoSuchElementException |
1. 元素定位器写错 2. 页面未加载完 3. 元素在iframe/frame内 4. 元素在Shadow DOM内 |
1. 用浏览器开发者工具 Ctrl+F 验证定位器 2. 增加显式等待 3. 使用 driver.switchTo().frame() 切换 4. 使用JavaScript Executor穿透Shadow DOM |
ElementNotInteractableException |
1. 元素被遮挡(如弹窗) 2. 元素不可见( display:none ) 3. 元素未处于可交互状态(如disabled) |
1. 检查是否有遮挡物,等待其消失 2. 检查元素CSS属性 3. 使用 isEnabled() 判断 |
StaleElementReferenceException |
之前找到的元素,因为页面刷新或AJAX更新,已经“过时”了 | 重新定位元素 。不要在变量中长期持有WebElement对象,对于动态页面,每次操作前最好重新 findElement |
| 脚本运行慢 | 1. 使用了 Thread.sleep 2. 隐式等待时间设置过长 3. 网络或应用本身慢 |
1. 用显式等待替代硬等待 2. 合理设置超时时间 3. 分析网络请求,确认是环境问题 |
| 浏览器行为与手动操作不一致 | 1. 浏览器缩放比例不是100% 2. 浏览器安装了插件干扰 3. 视窗大小影响元素布局 |
1. 启动浏览器时添加参数 –force-device-scale-factor=1 2. 使用无痕模式或禁用扩展 3. 使用 driver.manage().window().setSize() 设置固定分辨率 |
8.2 核心调试技巧
-
截图 :在脚本失败时自动截图,是定位问题的“现场照片”。
try { // 某些可能失败的操作 } catch (Exception e) { File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(srcFile, new File(“/path/to/screenshot.png”)); throw e; // 重新抛出异常 }需要额外引入
org.apache.commons.io.FileUtils。 -
高亮元素 :在操作元素前,用JavaScript给它加个边框,方便在运行过程中观察。
public void highlightElement(WebDriver driver, WebElement element) { JavascriptExecutor js = (JavascriptExecutor) driver; js.executeScript(“arguments[0].style.border=’3px solid red’”, element); try { Thread.sleep(500); } catch (InterruptedException e) {} // 暂停一下便于观察 } -
打印页面源码或元素HTML :当定位器失效时,看看当时的页面结构到底是什么样的。
System.out.println(driver.getPageSource()); // 慎用,可能很长 System.out.println(element.getAttribute(“outerHTML”)); // 查看单个元素 -
使用IDE的调试模式 :在关键步骤打上断点,逐步执行,观察变量状态,这是最强大的调试手段。
最后的小建议 :自动化测试脚本不是一蹴而就的,尤其是面对复杂的Web应用。保持耐心,从最简单的流程开始,逐步增加复杂度。每次遇到问题并解决它,都是对你定位器和脚本设计能力的一次提升。把环境搭好,把第一个脚本跑通,你就已经成功了一大半。剩下的,就是在不断的项目实践中,去积累更多关于等待策略、框架设计(如TestNG/JUnit)、报告生成和持续集成的经验了。
更多推荐


所有评论(0)