一、Selenium基础理论与环境搭建
1.1 Selenium简介与核心组件
Selenium是一个开源的Web自动化测试框架,支持多浏览器、多语言(Java、Python等),核心组件包括:
- WebDriver:通过浏览器驱动直接控制浏览器,模拟用户操作(点击、输入等),无侵入性。
- IDE:浏览器插件,支持录制/回放操作,适合快速生成脚本。
- Grid:分布式测试工具,支持多节点并行执行测试用例,提升效率。
Selenium 4.x(2025年最新版本为4.18)的核心特性包括:
- W3C WebDriver协议标准化:无需JSON Wire协议编解码,直接与浏览器通信,稳定性提升。
- Chrome DevTools Protocol(CDP)支持:原生集成网络监控、性能分析、地理位置模拟等高级功能。
- 相对定位器:通过
above()
、below()
、toLeftOf()
等方法基于元素相对位置定位。 - Selenium Manager:自动管理浏览器驱动(如ChromeDriver),无需手动下载配置。
1.2 环境搭建步骤
1.2.1 Java环境配置
- 安装JDK:推荐Java 11+,从Oracle官网下载对应版本,安装时勾选“Add to PATH”。
- 验证安装:命令行输入
java -version
,输出类似java version "17.0.10"
即成功。
1.2.2 Maven项目配置
- 创建Maven项目:使用IDE(如IntelliJ IDEA)创建Maven项目,在
pom.xml
中添加依赖:<!-- Selenium Java依赖 --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.18.0</version> </dependency> <!-- WebDriverManager(自动管理驱动) --> <dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>5.6.0</version> <scope>test</scope> </dependency> <!-- TestNG测试框架 --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.8.0</version> <scope>test</scope> </dependency>
1.2.3 浏览器驱动自动管理
通过WebDriverManager自动下载并配置驱动,无需手动管理版本:
<!-- Selenium Java依赖 -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.0</version>
</dependency>
<!-- WebDriverManager(自动管理驱动) -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
<!-- TestNG测试框架 -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.8.0</version>
<scope>test</scope>
</dependency>
二、核心API与元素操作
2.1 元素定位策略
Selenium提供8种定位方式,按优先级排序如下:
定位方式 | 语法示例 | 适用场景 |
---|---|---|
ID | driver.findElement(By.id("kw")) |
元素有唯一ID属性 |
CSS选择器 | driver.findElement(By.cssSelector(".s_ipt")) |
复杂样式匹配或动态属性 |
XPath | driver.findElement(By.xpath("//input[@name='wd']")) |
无固定属性时灵活定位 |
相对定位器(Selenium 4+) | driver.findElement(withTagName("input").below(usernameInput)) |
基于相邻元素位置定位 |
示例:使用XPath定位百度搜索框并输入文本
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 ElementLocation {
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com");
// XPath定位搜索框并输入"selenium"
WebElement searchBox = driver.findElement(By.xpath("//input[@id='kw']"));
searchBox.sendKeys("selenium");
// CSS选择器定位搜索按钮并点击
WebElement searchBtn = driver.findElement(By.cssSelector("#su"));
searchBtn.click();
driver.quit();
}
}
2.2 浏览器控制与等待机制
2.2.1 浏览器操作
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 ElementLocation {
public static void main(String[] args) {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com");
// XPath定位搜索框并输入"selenium"
WebElement searchBox = driver.findElement(By.xpath("//input[@id='kw']"));
searchBox.sendKeys("selenium");
// CSS选择器定位搜索按钮并点击
WebElement searchBtn = driver.findElement(By.cssSelector("#su"));
searchBtn.click();
driver.quit();
}
}
2.2.2 等待策略(解决动态元素加载问题)
- 隐式等待:全局设置,对所有元素查找生效
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
- 显式等待:针对特定元素设置条件等待
import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.ExpectedConditions; WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); WebElement dynamicElement = wait.until( ExpectedConditions.visibilityOfElementLocated(By.id("dynamicElement")) );
2.3 高级交互:Actions类
模拟鼠标、键盘操作(如拖拽、右键点击):
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement dynamicElement = wait.until(
ExpectedConditions.visibilityOfElementLocated(By.id("dynamicElement"))
);
三、高级设计模式:PO模式与数据驱动
3.1 Page Object Model(PO模式)
核心思想:将页面元素和操作封装为类,实现测试逻辑与页面细节分离,提升代码复用性和维护性。
3.1.1 目录结构
src/test/java
├── pages // 页面对象类
│ ├── BasePage.java // 基类,封装公共方法
│ ├── LoginPage.java // 登录页面对象
│ └── HomePage.java // 首页面对象
└── tests // 测试用例
└── LoginTest.java // 登录测试
3.1.2 实现示例
BasePage.java(基类):
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.time.Duration;
public class BasePage {
protected WebDriver driver;
protected WebDriverWait wait;
public BasePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
// 封装元素等待与点击
protected void click(WebElement element) {
wait.until(ExpectedConditions.elementToBeClickable(element)).click();
}
// 封装元素输入
protected void sendKeys(WebElement element, String text) {
wait.until(ExpectedConditions.visibilityOf(element)).sendKeys(text);
}
}
LoginPage.java(登录页面对象):
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class LoginPage extends BasePage {
// 元素定位
private By usernameInput = By.id("username");
private By passwordInput = By.id("password");
private By loginBtn = By.id("loginBtn");
public LoginPage(WebDriver driver) {
super(driver);
}
// 页面操作
public void inputUsername(String username) {
WebElement element = driver.findElement(usernameInput);
sendKeys(element, username);
}
public void inputPassword(String password) {
WebElement element = driver.findElement(passwordInput);
sendKeys(element, password);
}
public HomePage clickLoginBtn() {
WebElement element = driver.findElement(loginBtn);
click(element);
return new HomePage(driver); // 跳转到首页
}
}
LoginTest.java(测试用例):
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import io.github.bonigarcia.wdm.WebDriverManager;
public class LoginTest {
private WebDriver driver;
@BeforeMethod
public void setup() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.get("https://example.com/login");
}
@Test
public void testValidLogin() {
LoginPage loginPage = new LoginPage(driver);
loginPage.inputUsername("testuser");
loginPage.inputPassword("testpass");
HomePage homePage = loginPage.clickLoginBtn();
// 断言登录成功(示例)
assert homePage.getWelcomeText().contains("Welcome");
}
@AfterMethod
public void teardown() {
if (driver != null) {
driver.quit();
}
}
}
3.2 数据驱动测试(DDT)
核心思想:测试数据与脚本分离,通过外部文件(Excel、CSV)或数据库驱动测试用例,覆盖多场景。
3.2.1 使用TestNG的@DataProvider
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class DataDrivenTest {
// 数据提供者:返回二维数组(测试数据)
@DataProvider(name = "loginData")
public Object[][] provideData() {
return new Object[][]{
{"validUser", "validPass", "登录成功"},
{"invalidUser", "invalidPass", "用户名或密码错误"}
};
}
// 测试方法:使用数据提供者
@Test(dataProvider = "loginData")
public void testLogin(String username, String password, String expectedResult) {
// 执行登录操作并验证结果
System.out.println("用户名:" + username + ",预期结果:" + expectedResult);
}
}
3.2.2 读取Excel数据(Apache POI)
添加POI依赖:
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency>
Excel读取工具类:
import org.apache.poi.ss.usermodel.*; import java.io.FileInputStream; import java.io.IOException; public class ExcelUtil { public static Object[][] readExcel(String filePath, String sheetName) throws IOException { Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath)); Sheet sheet = workbook.getSheet(sheetName); int rowCount = sheet.getPhysicalNumberOfRows(); int colCount = sheet.getRow(0).getPhysicalNumberOfCells(); Object[][] data = new Object[rowCount - 1][colCount]; for (int i = 1; i < rowCount; i++) { Row row = sheet.getRow(i); for (int j = 0; j < colCount; j++) { Cell cell = row.getCell(j); data[i - 1][j] = cell.getStringCellValue(); } } workbook.close(); return data; } }
测试用例集成:
@DataProvider(name = "excelData") public Object[][] getExcelData() throws IOException { return ExcelUtil.readExcel("src/test/resources/loginData.xlsx", "Sheet1"); } @Test(dataProvider = "excelData") public void testLoginWithExcel(String username, String password, String expected) { // 执行测试逻辑 }
四、项目实战:电商网站登录与购物流程
4.1 项目结构
src/test/java
├── pages // 页面对象
│ ├── LoginPage.java
│ ├── HomePage.java
│ ├── ProductPage.java
│ └── CartPage.java
├── tests // 测试用例
│ ├── LoginTest.java
│ └── ShoppingTest.java
├── utils // 工具类
│ ├── ExcelUtil.java
│ └── LogUtil.java
└── resources // 测试数据
└── testData.xlsx
4.2 核心场景实现:商品加入购物车
public class ShoppingTest {
private WebDriver driver;
private LoginPage loginPage;
private HomePage homePage;
private ProductPage productPage;
private CartPage cartPage;
@BeforeMethod
public void setup() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
loginPage = new LoginPage(driver);
homePage = new HomePage(driver);
productPage = new ProductPage(driver);
cartPage = new CartPage(driver);
}
@Test(dataProvider = "productData", dataProviderClass = ExcelUtil.class)
public void testAddToCart(String username, String password, String productName) {
// 登录
driver.get("https://example.com/login");
loginPage.inputUsername(username);
loginPage.inputPassword(password);
loginPage.clickLoginBtn();
// 搜索商品
homePage.searchProduct(productName);
homePage.clickSearchResult(productName);
// 加入购物车
productPage.clickAddToCart();
// 验证购物车
cartPage.gotoCart();
assert cartPage.isProductInCart(productName);
}
@AfterMethod
public void teardown() {
driver.quit();
}
}
五、常见问题与解决方案
5.1 元素定位失败
- 动态ID/属性:使用XPath/CSS模糊匹配(如
contains(@class, 'btn')
)。 - iframe嵌套:先切换到iframe再操作元素:
driver.switchTo().frame("iframeId"); // 切换到iframe driver.switchTo().defaultContent(); // 返回主文档
5.2 浏览器兼容性
- Chrome For Testing:固定浏览器版本,避免自动更新影响测试:
# 通过npm安装特定版本Chrome For Testing npx @puppeteer/browsers install chrome@120.0.6099.0
5.3 测试速度优化
- Headless模式:无界面运行浏览器,节省资源:
ChromeOptions options = new ChromeOptions(); options.addArguments("--headless=new"); // Selenium 4.10+语法 WebDriver driver = new ChromeDriver(options);
- 并行执行:TestNG配置多线程执行测试用例:
<suite name="ParallelSuite" parallel="methods" thread-count="5"> <test name="Test1"> <classes> <class name="tests.ShoppingTest"/> </classes> </test> </suite>
六、高级应用:CDP协议与持续集成
6.1 Chrome DevTools Protocol(CDP)
模拟网络条件、地理位置等高级功能:
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import java.util.HashMap;
import java.util.Map;
public class CDPExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
DevTools devTools = ((ChromeDriver) driver).getDevTools();
devTools.createSession();
// 模拟5G网络
Map<String, Object> networkConditions = new HashMap<>();
networkConditions.put("offline", false);
networkConditions.put("latency", 20); // 延迟20ms
networkConditions.put("downloadThroughput", 20 * 1024 * 1024); // 20Mbps
driver.executeCdpCommand("Network.emulateNetworkConditions", networkConditions);
driver.get("https://example.com");
driver.quit();
}
}
6.2 持续集成(Jenkins)
- 配置Jenkins任务:拉取代码 → 执行Maven命令(
mvn test
)。 - 生成测试报告:TestNG默认生成报告,或集成Allure报告:
<dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-testng</artifactId> <version>2.24.0</version> <scope>test</scope> </dependency>
总结
本教程从基础环境搭建到高级设计模式,全面覆盖了Selenium Java版UI自动化测试的核心知识点。通过PO模式实现代码解耦,结合数据驱动提升测试覆盖率,配合CDP协议和持续集成构建企业级测试框架。实际应用中需注意元素定位策略优化、动态内容处理及测试效率提升,逐步构建稳定、可维护的自动化测试体系。