当前位置: 首页 > web >正文

Selenium+Java 自动化测试入门到实践:从环境搭建到元素操作

在自动化测试领域,Selenium 凭借其强大的跨浏览器兼容性和灵活的 API,成为 Web 应用测试的首选工具。而 Java 作为一门稳定且广泛应用的编程语言,与 Selenium 结合能构建出高效、可维护的自动化测试框架。本文将从环境搭建开始,逐步介绍 Selenium+Java 的核心用法,帮助新手快速上手。

一、环境搭建:让工具跑起来

1. 安装 Java 开发环境

Selenium 的 Java 客户端需要依赖 JDK,建议安装 JDK 8 及以上版本。安装完成后,需配置环境变量:

  • 新建JAVA_HOME,指向 JDK 安装目录(如C:\Program Files\Java\jdk1.8.0_301
  • Path中添加%JAVA_HOME%\bin%JAVA_HOME%\jre\bin
  • 配置CLASSPATH.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar

通过java -versionjavac -version命令验证安装是否成功。

2. 配置开发工具

推荐使用 IntelliJ IDEA 或 Eclipse 作为开发 IDE。以 IntelliJ IDEA 为例,新建 Maven 项目后,在pom.xml中添加 Selenium 依赖:

Maven 会自动下载 Selenium 相关的 JAR 包,无需手动导入。

3. 下载浏览器驱动

Selenium 需要通过驱动程序与浏览器交互,不同浏览器需对应不同驱动:

  • Chrome:ChromeDriver(版本需与浏览器版本匹配)
  • Firefox:GeckoDriver
  • Edge:EdgeDriver

下载后将驱动文件放在无空格的目录下(如D:\drivers),并将该目录添加到系统Path中,或在代码中指定驱动路径。

二、第一个 Selenium+Java 程序:打开百度首页

环境就绪后,我们来编写第一个自动化脚本,实现打开 Chrome 浏览器并访问百度首页的功能:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;public class FirstSeleniumTest {public static void main(String[] args) {// 初始化WebDriver实例(Chrome浏览器)WebDriver driver = new ChromeDriver();// 打开百度首页driver.get("https://www.baidu.com");// 打印页面标题System.out.println("页面标题:" + driver.getTitle());// 等待3秒后关闭浏览器try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}// 关闭浏览器driver.quit();}
}

运行代码后,会自动启动 Chrome 浏览器并打开百度首页,控制台输出页面标题,3 秒后浏览器自动关闭。这里的WebDriver是 Selenium 的核心接口,封装了浏览器的各种操作方法。

三、核心操作:元素定位与交互

自动化测试的核心是与页面元素交互,而元素定位是前提。Selenium 提供了 8 种元素定位方式,常用的有以下几种:

1. 元素定位方法

  • id:通过元素的id属性定位(唯一性高,优先使用)
    WebElement searchBox = driver.findElement(By.id("kw")); // 百度搜索框
    
  • name:通过元素的name属性定位
    WebElement searchBox = driver.findElement(By.name("wd"));
    
  • xpath:通过 XML 路径语言定位,支持复杂场景
    // 绝对路径(不推荐,易受页面结构变化影响)
    WebElement searchBtn = driver.findElement(By.xpath("/html/body/div[1]/div[1]/div[5]/div/div/form/span[2]/input"));// 相对路径(推荐,更灵活)
    WebElement searchBtn = driver.findElement(By.xpath("//input[@value='百度一下']"));
    
  • cssSelector:通过 CSS 选择器定位,速度比 xpath 快
    WebElement searchBtn = driver.findElement(By.cssSelector("#su")); // 百度搜索按钮
    

2. 元素交互操作

定位到元素后,可执行点击、输入、清除等操作:

// 定位搜索框并输入内容
WebElement searchBox = driver.findElement(By.id("kw"));
searchBox.sendKeys("Selenium+Java");// 定位搜索按钮并点击
WebElement searchBtn = driver.findElement(By.id("su"));
searchBtn.click();// 清除输入框内容
searchBox.clear();

四、进阶技巧:等待机制与窗口切换

在实际测试中,页面加载、异步请求等可能导致元素未及时出现,直接操作会抛出异常。Selenium 提供了三种等待机制解决这一问题:

1. 等待机制

  • 隐式等待:设置全局等待时间,在规定时间内轮询查找元素
    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    
  • 显式等待:针对特定元素设置等待条件和超时时间
    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    WebElement result = wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//div[contains(@class,'result')]")));
    
  • 线程休眠:强制等待(不推荐,影响执行效率)
    Thread.sleep(2000);
    

2. 窗口切换

当页面打开新窗口时,需切换到对应窗口才能操作其中的元素:

// 获取当前所有窗口句柄
Set<String> windowHandles = driver.getWindowHandles();
List<String> handlesList = new ArrayList<>(windowHandles);// 切换到新窗口(假设新窗口是第二个打开的)
driver.switchTo().window(handlesList.get(1));// 切回原窗口
driver.switchTo().window(handlesList.get(0));

五、高级元素操作与 JavaScript 执行

1. 复杂表单处理

对于下拉框、复选框、单选按钮等特殊表单元素,Selenium 提供了专门的处理类:

// 处理下拉框(Select类)
WebElement selectElement = driver.findElement(By.id("selectId"));
Select select = new Select(selectElement);// 通过索引选择(从0开始)
select.selectByIndex(1);
// 通过可见文本选择
select.selectByVisibleText("选项二");
// 通过value属性选择
select.selectByValue("option2");// 获取所有选项
List<WebElement> options = select.getOptions();// 处理复选框
WebElement checkbox = driver.findElement(By.id("checkbox1"));
if (!checkbox.isSelected()) {checkbox.click();
}// 处理单选按钮
List<WebElement> radios = driver.findElement(By.name("radioGroup"));
for (WebElement radio : radios) {if (radio.getAttribute("value").equals("male")) {radio.click();break;}
}

2. 文件上传与下载

文件上传和下载是 Web 测试中常见场景:

// 文件上传(input标签type=file)
WebElement uploadInput = driver.findElement(By.id("uploadFile"));
// 直接发送文件路径即可,无需点击上传按钮
uploadInput.sendKeys("D:\\test\\upload.txt");// 文件下载(配置浏览器下载路径)
ChromeOptions options = new ChromeOptions();
// 设置下载路径
Map<String, Object> prefs = new HashMap<>();
prefs.put("download.default_directory", "D:\\test\\downloads");
// 禁止下载弹窗
prefs.put("download.prompt_for_download", false);
options.setExperimentalOption("prefs", prefs);// 用配置好的选项初始化driver
WebDriver driver = new ChromeDriver(options);

3. 执行 JavaScript 代码

对于 Selenium 原生 API 难以实现的操作(如滚动页面、修改元素属性),可以通过执行 JavaScript 实现:

JavascriptExecutor js = (JavascriptExecutor) driver;// 滚动到页面底部
js.executeScript("window.scrollTo(0, document.body.scrollHeight)");// 滚动到指定元素
WebElement target = driver.findElement(By.id("targetId"));
js.executeScript("arguments[0].scrollIntoView();", target);// 修改元素属性(如移除readonly属性)
js.executeScript("arguments[0].removeAttribute('readonly')", element);// 获取页面标题(通过JS)
String title = (String) js.executeScript("return document.title");

六、测试框架设计与优化

1. 基础框架结构

一个规范的 Selenium 测试框架应包含以下结构:

src/main/java
├── common/           // 公共工具类
│   ├── DriverUtil.java  // 驱动管理
│   ├── WaitUtil.java    // 等待工具
│   └── ScreenShotUtil.java // 截图工具
├── page/             // 页面对象
│   ├── LoginPage.java
│   └── HomePage.java
└── test/             // 测试用例├── LoginTest.java└── HomeTest.java

2. 页面对象模型(POM)

POM 模式将页面元素和操作封装到页面对象类中,提高代码复用性和可维护性:

// 登录页面对象
public class LoginPage {private WebDriver driver;private WebDriverWait wait;// 元素定位@FindBy(id = "username")private WebElement usernameInput;@FindBy(id = "password")private WebElement passwordInput;@FindBy(id = "loginBtn")private WebElement loginButton;// 构造方法public LoginPage(WebDriver driver) {this.driver = driver;this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));PageFactory.initElements(driver, this); // 初始化页面元素}// 页面操作public void enterUsername(String username) {usernameInput.sendKeys(username);}public void enterPassword(String password) {passwordInput.sendKeys(password);}public HomePage clickLogin() {loginButton.click();return new HomePage(driver); // 登录后跳转到首页}public void login(String username, String password) {enterUsername(username);enterPassword(password);clickLogin();}
}

使用 POM 后的测试用例更加简洁:

public class LoginTest {private WebDriver driver;private LoginPage loginPage;@BeforeEachpublic void setUp() {driver = DriverUtil.getDriver();driver.get("https://example.com/login");loginPage = new LoginPage(driver);}@Testpublic void testSuccessfulLogin() {loginPage.login("testuser", "testpass");// 验证登录成功Assertions.assertTrue(driver.getCurrentUrl().contains("/home"));}@AfterEachpublic void tearDown() {DriverUtil.quitDriver();}
}

3. 数据驱动测试

结合 TestNG 和 Excel 实现数据驱动测试,用不同数据执行相同测试逻辑:

// 读取Excel数据工具类
public class ExcelUtil {public static Object[][] readTestData(String filePath, String sheetName) {// 实现Excel读取逻辑,返回二维数组// 每行代表一组测试数据,每列代表一个参数}
}// 数据驱动测试用例
public class LoginDataDrivenTest {private WebDriver driver;private LoginPage loginPage;@BeforeMethodpublic void setUp() {driver = DriverUtil.getDriver();driver.get("https://example.com/login");loginPage = new LoginPage(driver);}@Test(dataProvider = "loginData")public void testLoginWithDifferentData(String username, String password, String expectedResult) {loginPage.enterUsername(username);loginPage.enterPassword(password);loginPage.clickLogin();if (expectedResult.equals("success")) {Assertions.assertTrue(driver.getCurrentUrl().contains("/home"));} else {Assertions.assertTrue(driver.findElement(By.cssSelector(".error-msg")).isDisplayed());}}@DataProvider(name = "loginData")public Object[][] provideTestData() {return ExcelUtil.readTestData("src/test/resources/loginData.xlsx", "Sheet1");}@AfterMethodpublic void tearDown() {DriverUtil.quitDriver();}
}

七、测试报告与持续集成

1. 生成美观的测试报告

使用 ExtentReports 生成详细的 HTML 测试报告:

public class ExtentReportUtil {private static ExtentReports extent;private static ExtentTest test;public static void initReport() {extent = new ExtentReports();File reportDir = new File("test-reports");if (!reportDir.exists()) {reportDir.mkdir();}ExtentSparkReporter spark = new ExtentSparkReporter("test-reports/result.html");extent.attachReporter(spark);}public static void createTest(String testName) {test = extent.createTest(testName);}public static void logPass(String message) {test.pass(message);}public static void logFail(String message) {test.fail(message);// 失败时截图String screenshotPath = ScreenShotUtil.takeScreenshot(driver, "fail");test.addScreenCaptureFromPath(screenshotPath);}public static void flushReport() {extent.flush();}
}

2. 集成到 CI/CD 流程

将 Selenium 测试集成到 Jenkins 等 CI 工具,实现自动化构建和测试:

  1. 在项目中添加 Maven Surefire 插件,用于执行测试用例:
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>3.0.0-M5</version><configuration><suiteXmlFiles><suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile></suiteXmlFiles></configuration></plugin></plugins>
</build>
  1. 在 Jenkins 中配置:
    • 拉取代码仓库
    • 执行mvn clean test命令
    • 配置测试报告展示(ExtentReports 或 TestNG 报告)
    • 设置邮件通知,发送测试结果

八、常见问题与解决方案

1. 元素定位不稳定

  • 优先使用显式等待,而非隐式等待或线程休眠
  • 避免使用绝对 XPath,改用相对 XPath 并结合多种属性定位
  • 对于动态 ID,使用包含部分固定文本的定位方式://div[contains(@id, 'prefix_')]

2. 浏览器兼容性问题

  • 使用 WebDriverManager 管理不同浏览器驱动,自动匹配版本:
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
  • 编写测试基类,通过参数控制启动不同浏览器:
public class TestBase {protected WebDriver driver;@Parameters("browser")@BeforeMethodpublic void setUp(String browser) {if (browser.equals("chrome")) {driver = new ChromeDriver();} else if (browser.equals("firefox")) {driver = new FirefoxDriver();} else if (browser.equals("edge")) {driver = new EdgeDriver();}driver.manage().window().maximize();}
}

3. 执行速度优化

  • 减少不必要的等待时间,合理设置超时参数
  • 避免在循环中频繁查找元素,可一次查找后缓存
  • 使用 Headless 模式运行浏览器(无界面模式):
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless=new"); // Chrome 112+版本
WebDriver driver = new ChromeDriver(options);

九、总结与学习资源

Selenium+Java 的学习是一个循序渐进的过程,从基础操作到框架搭建需要不断实践和总结

自动化测试的核心价值在于提高测试效率和回归测试覆盖率,在实际项目中,应根据需求选择合适的测试场景进行自动化,避免盲目追求自动化率。随着经验的积累,你会逐渐掌握如何设计出稳定、高效、易维护的自动化测试框架。

http://www.xdnf.cn/news/16138.html

相关文章:

  • TIM定时中断
  • 一些Avalonia与WPF内容的对应关系和不同用法
  • Java从入门到精通!第十一天(Java常见的数据结构)
  • 数据库设计mysql篇
  • 嵌入式学习-土堆目标检测(3)-day27
  • 【iOS】SideTable
  • 【深度解析】从AWS re_Invent 2025看云原生技术发展趋势
  • C语言(20250722)
  • 网络编程---TCP协议
  • 跨越语言壁垒!ZKmall开源商城多语言架构如何支撑电商全球化布局
  • libgmp库(GNU高精度算术库)介绍
  • mac实现sudo命切换node版本
  • netty的编解码器,以及内置的编解码器
  • OpenCV 零基础到项目实战 | DAY 1:图像基础与核心操作
  • LLC协议
  • mysql_innodb_cluster_metadata源数据库
  • Vue3 面试题及详细答案120道(31-45 )
  • Web3面试题
  • 智慧能源合同解决方案
  • 【接口自动化】pytest的基本使用
  • XML高效处理类 - 专为Office文档XML处理优化
  • Aspose.Cells 应用案例:法国能源企业实现能源数据报告Excel自动化
  • Python通关秘籍(五)数据结构——元组
  • Rocky Linux 9 快速安装 Node.js
  • 3.5 模块化编程实践
  • 【数据结构初阶】--栈和队列(二)
  • Python之格式化Conda中生成的requirements.txt
  • 我的第一个开源项目 -- 实时语音识别工具
  • 数据库表介绍
  • 算法提升之字符串回文处理-(manacher)