Selenium with Java 完整教程
目录
-
- 1 前置条件
- 2 安装和配置 IDE (IntelliJ IDEA)
- 3 创建 Maven 项目
- 4 添加 Selenium 依赖
- 5 下载浏览器驱动
-
- 1 Selenium WebDriver 架构简介
- 2 第一个自动化脚本:打开和关闭浏览器
- 3 元素定位策略
- 4 浏览器操作
- 5 元素交互
- 6 等待策略
- 7 下拉框处理
- 8 弹窗处理
- 9 多窗口/标签页处理
- 10 JavaScript 执行器
- 11 截图
-
- 1 Page Object Model (POM) 设计模式
- 2 数据驱动测试 (使用 TestNG 和 DataProvider)
- 3 集成 TestNG 框架
- 4 使用 Selenium Grid 进行分布式测试
-
- 1 项目目标
- 2 项目结构
- 3 代码实现
第一部分:环境准备
1 前置条件
在开始之前,请确保你已经安装了以下软件:
- Java Development Kit (JDK): 建议使用 JDK 8 或更高版本,你可以从 Oracle 官网 下载。
- 集成开发环境: 推荐使用 IntelliJ IDEA (社区版免费) 或 Eclipse,本教程以 IntelliJ IDEA 为例。
- 浏览器: 本教程使用 Google Chrome。
2 安装和配置 IDE (IntelliJ IDEA)
- 下载并安装 IntelliJ IDEA Community Edition。
- 启动 IDE,接受许可协议。
- 你可以导入之前的设置或选择 "Do not import settings"。
3 创建 Maven 项目
Maven 是一个项目管理和构建自动化工具,可以非常方便地管理项目依赖(Selenium 库)。
- 在 IntelliJ IDEA 中,点击
File->New->Project。 - 在左侧面板选择
Maven。 - 确保
Create from archetype选项是未选中的状态,然后点击Next。 - 填写
GroupId(通常为你的组织或个人域名,如com.example) 和ArtifactId(项目名,如selenium-tutorial),点击Next。 - 选择你的 Maven 设置(通常使用默认即可),点击
Next。 - 选择项目存放位置,点击
Finish。 - 等待 Maven 下载完项目模板和依赖后,你的项目结构就创建好了。
4 添加 Selenium 依赖
我们需要在 pom.xml 文件中添加 Selenium WebDriver 的依赖。
- 打开
pom.xml文件。 - 在
<dependencies>标签内,添加以下内容:
<dependencies>
<!-- Selenium Java WebDriver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.15.0</version> <!-- 建议使用最新稳定版 -->
</dependency>
<!-- TestNG for test management -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.8.0</version> <!-- 建议使用最新稳定版 -->
</dependency>
</dependencies>
- IntelliJ IDEA 会自动识别并下载这些依赖,你也可以点击 Maven 窗口(右侧)中的
Reload All Maven Projects按钮手动刷新。
5 下载浏览器驱动
Selenium 本身不控制浏览器,它通过一个叫 WebDriver 的库与浏览器进行通信,WebDriver 是一个与浏览器绑定的可执行程序。
以 Chrome 为例:
- 确定你的 Chrome 浏览器版本:在 Chrome 地址栏输入
chrome://version/查看。 - 下载对应版本的 WebDriver:
- 访问 Chrome for Testing availability。
- 找到与你浏览器版本最接近的
chromedriver版本。 - 下载对应你操作系统的
zip包(如win32,mac-x64,linux64)。
- 配置 WebDriver 路径:
- 方法一(推荐,无需配置环境变量):将下载的
chromedriver.exe(Windows) 或chromedriver(Mac/Linux) 文件放在你的项目根目录下(与pom.xml同级)。 - 方法二:将
chromedriver所在目录添加到系统的PATH环境变量中。
- 方法一(推荐,无需配置环境变量):将下载的
注意:Selenium 4 在很多情况下可以自动下载和管理驱动,但手动下载和控制版本更稳定,是生产环境的最佳实践。
第二部分:Selenium 核心概念与 API
1 Selenium WebDriver 架构简介
理解这个架构有助于你更好地使用 Selenium。
- 你的测试脚本: 用 Java 编写的代码。
- Selenium WebDriver API: Java 库,提供了与浏览器交互的接口。
- WebDriver 浏览器驱动: 一个可执行文件(如
chromedriver),负责将 API 调用转换成浏览器能理解的命令。 - 浏览器: 实际执行操作的软件(如 Chrome, Firefox)。
2 第一个自动化脚本
在你的 src/main/java 目录下创建一个新的 Java 类,命名为 FirstScript。
package com.example;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
public class FirstScript {
@Test
public void testGoogleSearch() {
// 1. 设置 WebDriver 路径 (如果方法一未将驱动放在项目根目录)
// System.setProperty("webdriver.chrome.driver", "path/to/your/chromedriver");
// 2. 创建 WebDriver 实例,它会打开一个新的浏览器窗口
WebDriver driver = new ChromeDriver();
try {
// 3. 导航到指定网址
driver.get("https://www.google.com");
// 4. 最大化浏览器窗口
driver.manage().window().maximize();
// 5. 获取页面标题并打印
String title = driver.getTitle();
System.out.println("页面标题是: " + title);
// 6. 验证标题是否正确
if (title.equals("Google")) {
System.out.println("测试通过:标题匹配!");
} else {
System.out.println("测试失败:标题不匹配!");
}
} finally {
// 7. 关闭浏览器
// driver.close(); // 关闭当前标签页
driver.quit(); // 关闭整个浏览器进程,推荐使用
}
}
}
如何运行:
在 @Test 方法上右键,选择 Run 'testGoogleSearch()'。
3 元素定位策略
自动化测试的核心就是找到页面上的元素(按钮、输入框、链接等)并进行操作,Selenium 提供了多种定位方式。
| 定位方式 | Java 代码示例 | 描述 |
|---|---|---|
| ID | driver.findElement(By.id("element_id")); |
最推荐,通常是唯一的。 |
| Name | driver.findElement(By.name("element_name")); |
可能不唯一,慎用。 |
| ClassName | driver.findElement(By.className("class_name")); |
可能有多个元素共享同一个 class。 |
| Link Text | driver.findElement(By.linkText("点击这里")); |
专门用于定位 <a> 标签的完整文本。 |
| Partial Link Text | driver.findElement(By.partialLinkText("点击")); |
定位 <a> 标签的部分文本,不推荐,可能不唯一。 |
| CSS Selector | driver.findElement(By.cssSelector("#id")); |
非常强大和灵活,推荐作为 ID 之后的第二选择。 |
| XPath | driver.findElement(By.xpath("//input[@id='element_id']")); |
非常强大,可以遍历 DOM 树,当没有 ID/CSS 时使用。 |
示例:
假设 HTML 为 <input type="text" id="username" name="user" class="form-control">
import org.openqa.selenium.By;
// 使用 ID
WebElement usernameField_byId = driver.findElement(By.id("username"));
// 使用 CSS Selector
WebElement usernameField_byCss = driver.findElement(By.cssSelector("#username")); // ID
WebElement usernameField_byCss2 = driver.findElement(By.cssSelector("input.form-control")); // Tag and Class
// 使用 XPath
WebElement usernameField_byXpath = driver.findElement(By.xpath("//input[@id='username']")); // 使用 id 属性
WebElement usernameField_byXpath2 = driver.findElement(By.xpath("//*[@id='username']")); // 使用任意标签和 id 属性
4 浏览器操作
// 导航
driver.get("https://www.example.com");
driver.navigate().to("https://www.google.com");
// 前进/后退 (像浏览器按钮一样)
driver.navigate().back();
driver.navigate().forward();
// 刷新
driver.navigate().refresh();
// 窗口管理
driver.manage().window().maximize(); // 最大化
driver.manage().window().minimize(); // 最小化
driver.manage().window().fullscreenWindow(); // 全屏
// 获取当前 URL
String currentUrl = driver.getCurrentUrl();
System.out.println("当前 URL: " + currentUrl);
5 元素交互
一旦你通过 findElement 找到了一个 WebElement 对象,你就可以对它进行操作。
// 假设已经找到了 usernameField 和 passwordField
WebElement usernameField = driver.findElement(By.id("username"));
WebElement passwordField = driver.findElement(By.id("password"));
WebElement loginButton = driver.findElement(By.id("login-btn"));
// 清空输入框(重要!)
usernameField.clear();
passwordField.clear();
// 在输入框中输入文本
usernameField.sendKeys("my_test_user");
passwordField.sendKeys("my_secret_password");
// 点击按钮
loginButton.click();
// 获取元素的文本
WebElement welcomeMessage = driver.findElement(By.id("welcome"));
String text = welcomeMessage.getText();
System.out.println("欢迎信息: " + text);
// 获取元素的属性值
String type = usernameField.getAttribute("type");
System.out.println("输入框类型: " + type);
6 等待策略
这是 Selenium 自动化测试中最重要也最容易出错的部分,如果页面元素加载慢,你的脚本执行得太快,就会导致 NoSuchElementException。
有三种等待方式:
-
硬性等待 (不推荐):
Thread.sleep(5000);让脚本暂停固定时间,这会大大降低测试效率,不推荐使用。 -
隐式等待: 在查找元素时,如果找不到,WebDriver 会等待一个指定的时间再去查找。
// 设置隐式等待,全局有效,通常在创建 driver 后设置一次 driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
- 缺点: 它会为
findElement和findElements的所有调用设置等待,如果你在等待一个元素 A,但元素 B 先出现,它也会浪费时间等待 A,即使你并不关心 A。
- 缺点: 它会为
-
显式等待 (强烈推荐): 针对某个特定的元素,设置一个条件,如果条件在指定时间内满足,就立即继续执行;如果超时,则抛出异常。
import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; // 创建 WebDriverWait 实例 WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // 等待元素可见 WebElement usernameField = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username"))); usernameField.sendKeys("test"); // 等待元素可点击 WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(By.id("login-btn"))); loginButton.click();- 优点: 精准、高效,只等待你需要的元素满足特定条件。
最佳实践: 优先使用显式等待,仅在必要时(如页面整体加载)配合使用隐式等待。
7 下拉框处理
对于 <select> 标签的下拉框,最好使用 Select 类。
import org.openqa.selenium.support.ui.Select;
// 假设 HTML 是 <select id="country"><option value="us">United States</option>...</select>
WebElement dropdownElement = driver.findElement(By.id("country"));
Select countryDropdown = new Select(dropdownElement);
// 1. 通过索引选择 (从0开始)
countryDropdown.selectByIndex(0); // 选择第一个选项
// 2. 通过 value 属性选择
countryDropdown.selectByValue("us"); // 选择 value="us" 的选项
// 3. 通过可见文本选择
countryDropdown.selectByVisibleText("United States");
// 获取当前选中的选项
WebElement selectedOption = countryDropdown.getFirstSelectedOption();
System.out.println("当前选中的是: " + selectedOption.getText());
// 检查下拉框是否是多选
System.out.println("是否是多选? " + countryDropdown.isMultiple());
8 弹窗处理
弹窗分为两种:Alert (JavaScript 弹窗) 和 Modal Dialog (HTML 模态框)。
Alert 处理:
// 触发一个 Alert 弹窗
driver.findElement(By.id("alert-button")).click();
// 切换到 Alert
Alert alert = driver.switchTo().alert();
// 获取 Alert 文本
String alertText = alert.getText();
System.out.println("Alert 文本: " + alertText);
// 点击 "确定" 按钮
alert.accept();
// 如果是 "确认/取消" 弹窗,可以点击 "取消"
// alert.dismiss();
Modal Dialog 处理:
Modal Dialog 实际上是 HTML 元素,通常位于一个 div 覆盖层上,处理方式是先找到该元素,然后进行交互。
// 假设模态框的 HTML 是 <div id="login-modal">...</div>
// 1. 触发模态框显示
driver.findElement(By.id("open-modal-btn")).click();
// 2. 等待模态框出现
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement modal = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("login-modal")));
// 3. 在模态框内定位元素并操作
WebElement modalUsername = modal.findElement(By.id("modal-username"));
WebElement modalPassword = modal.findElement(By.id("modal-password"));
modalUsername.sendKeys("user");
modalPassword.sendKeys("pass");
// 4. 点击模态框内的提交按钮
modal.findElement(By.id("modal-submit-btn")).click();
9 多窗口/标签页处理
当点击链接打开一个新标签页时,需要切换 WebDriver 的焦点。
// 获取当前窗口句柄 (Handle)
String originalWindow = driver.getWindowHandle();
// 点击一个会打开新标签页的链接
driver.findElement(By.linkText("打开新页面")).click();
// 循环遍历所有窗口句柄,直到找到新的窗口
for (String windowHandle : driver.getWindowHandles()) {
if (!windowHandle.equals(originalWindow)) {
driver.switchTo().window(windowHandle);
break;
}
}
// 现在在新标签页上操作
System.out.println("新标签页标题: " + driver.getTitle());
// 关闭当前标签页
driver.close();
// 切换回原始窗口
driver.switchTo().window(originalWindow);
10 JavaScript 执行器
有时需要执行一些 JavaScript 代码来辅助测试,比如滚动页面、修改元素属性等。
import org.openqa.selenium.JavascriptExecutor;
// 将 driver 转换为 JavascriptExecutor
JavascriptExecutor js = (JavascriptExecutor) driver;
// 1. 执行简单的 JS 脚本,获取返回值
String pageTitle = (String) js.executeScript("return document.title;");
System.out.println("通过 JS 获取的标题: " + pageTitle);
// 2. 滚动页面到某个元素
WebElement element = driver.findElement(By.id("some-element"));
js.executeScript("arguments[0].scrollIntoView(true);", element);
// 3. 高亮元素 (仅用于调试,不影响实际功能)
js.executeScript("arguments[0].style.border='3px solid red'", element);
11 截图
在测试失败时自动截图是至关重要的。
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
// 在 try-catch 块中执行测试
try {
// ... 你的测试代码 ...
} catch (Exception e) {
// 测试失败,截图
File screenshotFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
String screenshotName = "failure_screenshot_" + timestamp + ".png";
try {
FileUtils.copyFile(screenshotFile, new File("screenshots/" + screenshotName));
System.out.println("截图已保存到: screenshots/" + screenshotName);
} catch (IOException ioException) {
ioException.printStackTrace();
}
// 重新抛出异常,让测试框架知道失败了
throw e;
}
注意: 你需要在 pom.xml 中添加 commons-io 依赖。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
第三部分:高级主题与最佳实践
1 Page Object Model (POM) 设计模式
POM 是一种设计模式,用于提高测试代码的可维护性和可读性。
核心思想:
- Page 类: 每个页面(或一个重要的组件)都有一个对应的 Java 类。
- 封装: Page 类封装了该页面的所有元素定位和操作方法。
- 测试类: 测试类(测试脚本)只关注业务逻辑流程,不关心具体的元素定位细节。
示例:
LoginPage.java
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class LoginPage {
private WebDriver driver;
private WebDriverWait wait;
// 使用 Page Factory 注解来定位元素
@FindBy(id = "username")
private WebElement usernameInput;
@FindBy(id = "password")
private WebElement passwordInput;
@FindBy(id = "login-btn")
private WebElement loginButton;
@FindBy(id = "error-message")
private WebElement errorMessage;
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this); // 初始化 Page Factory
}
public void login(String username, String password) {
wait.until(ExpectedConditions.visibilityOf(usernameInput));
usernameInput.sendKeys(username);
passwordInput.sendKeys(password);
loginButton.click();
}
public String getErrorMessage() {
wait.until(ExpectedConditions.visibilityOf(errorMessage));
return errorMessage.getText();
}
}
LoginTest.java
package com.example.tests;
import com.example.pages.LoginPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class LoginTest {
WebDriver driver;
LoginPage loginPage;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.get("https://example.com/login");
loginPage = new LoginPage(driver);
}
@Test
public void successfulLoginTest() {
loginPage.login("valid_user", "valid_password");
// ... 验证登录成功后的页面 ...
Assert.assertTrue(driver.getTitle().contains("Dashboard"));
}
@Test
public void invalidCredentialsTest() {
loginPage.login("invalid_user", "wrong_password");
String error = loginPage.getErrorMessage();
Assert.assertEquals(error, "用户名或密码错误");
}
@AfterMethod
public void tearDown() {
driver.quit();
}
}
2 集成 TestNG 框架
TestNG 是一个强大的测试框架,提供了测试分组、依赖、参数化、并行执行等丰富功能。
- 确保
pom.xml中有 TestNG 依赖 (见 1.4)。 - 创建
testng.xml配置文件: 在项目根目录下创建testng.xml文件。<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd"> <suite name="Selenium Test Suite"> <test name="Login Tests"> <classes> <class name="com.example.tests.LoginTest"/> </classes> </test> </suite> - 运行测试:
在 IntelliJ IDEA 中,右键点击
testng.xml文件,选择Run 'testng.xml'。
3 数据驱动测试
使用 TestNG 的 @DataProvider 可以轻松实现数据驱动,即用不同的数据多次运行同一个测试方法。
LoginTest.java (修改版)
package com.example.tests;
// ... imports ...
public class LoginTest {
// ... setup and teardown methods ...
@DataProvider(name = "loginCredentials")
public Object[][] provideCredentials() {
return new Object[][] {
{ "valid_user", "valid_password", true, null }, // 用户名, 密码, 是否期望成功, 期望的错误信息
{ "invalid_user", "valid_password", false, "用户名或密码错误" },
{ "valid_user", "wrong_password", false, "用户名或密码错误" },
{ "", "", false, "用户名和密码不能为空" }
};
}
@Test(dataProvider = "loginCredentials")
public void loginTest(String username, String password, boolean shouldSucceed, String expectedError) {
loginPage.login(username, password);
if (shouldSucceed) {
// 验证登录成功
Assert.assertTrue(driver.getTitle().contains("Dashboard"));
} else {
// 验证登录失败
String actualError = loginPage.getErrorMessage();
Assert.assertEquals(actualError, expectedError);
}
}
}
第四部分:实战项目示例
1 项目目标
自动化测试一个简单的用户登录和搜索功能。
- 打开
https://the-internet.herokuapp.com/login。 - 使用不同的用户名和密码进行登录测试(成功和失败场景)。
- 登录成功后,导航到
https://the-internet.herokuapp.com/。 - 在搜索框中输入 "ab"。
- 验证搜索结果中是否包含 "Elemental Selenium"。
2 项目结构
遵循 POM 模式,项目结构如下:
selenium-tutorial/
├── pom.xml
├── src/
│ ├── main/
│ │ └── java/
│ │ └── com/
│ │ └── example/
│ │ ├── pages/
│ │ │ ├── LoginPage.java
│ │ │ └── HomePage.java
│ │ └── utils/
│ │ └── DriverManager.java (可选,用于集中管理 driver)
│ └── test/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── tests/
│ │ └── HerokuappTest.java
│ └── resources/
│ └── testng.xml
└── screenshots/
3 代码实现
src/main/java/com/example/pages/LoginPage.java
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public class LoginPage {
private final WebDriver driver;
private final WebDriverWait wait;
@FindBy(id = "username")
private WebElement usernameInput;
@FindBy(id = "password")
private WebElement passwordInput;
@FindBy(css = "button[type='submit']")
private WebElement loginButton;
@FindBy(id = "flash")
private WebElement flashMessage;
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this);
}
public void enterUsername(String username) {
wait.until(ExpectedConditions.visibilityOf(usernameInput));
usernameInput.sendKeys(username);
}
public void enterPassword(String password) {
passwordInput.sendKeys(password);
}
public void clickLoginButton() {
loginButton.click();
}
public String getFlashMessage() {
return flashMessage.getText();
}
public void login(String username, String password) {
enterUsername(username);
enterPassword(password);
clickLoginButton();
}
}
src/main/java/com/example/pages/HomePage.java
package com.example.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
public class HomePage {
private final WebDriver driver;
private final WebDriverWait wait;
@FindBy(name = "q")
private WebElement searchInput;
@FindBy(css = "ul li a")
private WebElement searchResults;
public HomePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
PageFactory.initElements(driver, this);
}
public void performSearch(String searchTerm) {
wait.until(ExpectedConditions.visibilityOf(searchInput));
searchInput.sendKeys(searchTerm);
// 这里可以添加点击搜索按钮的逻辑,如果有的话
// 假设输入后自动触发搜索
}
public boolean isSearchResultPresent(String expectedText) {
// 等待至少一个结果出现
wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(By.cssSelector("ul li a"), 0));
// 检查结果列表中是否包含期望的文本
return driver.findElements(By.xpath("//ul/li/a[contains(text(), '" + expectedText + "')]")).size() > 0;
}
}
src/test/java/com/example/tests/HerokuappTest.java
package com.example.tests;
import com.example.pages.HomePage;
import com.example.pages.LoginPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class HerokuappTest {
private WebDriver driver;
private LoginPage loginPage;
private HomePage homePage;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://the-internet.herokuapp.com/login");
loginPage = new LoginPage(driver);
homePage = new HomePage(driver);
}
@Test
public void testLoginAndSearch() {
// 1. 登录
loginPage.login("tomsmith", "SuperSecretPassword!");
// 2. 验证登录成功
String flashMessage = loginPage.getFlashMessage();
Assert.assertTrue(flashMessage.contains("You logged into a secure area!"));
// 3. 导航到主页 (如果登录后不在主页)
driver.get("https://the-internet.herokuapp.com/");
// 4. 执行搜索
homePage.performSearch("ab");
// 5. 验证搜索结果
Assert.assertTrue(homePage.isSearchResultPresent("Elemental Selenium"), "搜索结果中未找到 'Elemental Selenium'");
}
@AfterMethod
public void tearDown() throws IOException {
// 简单的截图逻辑,无论成功失败都截图
try {
File screenshotFile = ((org.openqa.selenium.TakesScreenshot)driver).getScreenshotAs(org.openqa.selenium.OutputType.FILE);
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
FileUtils.copyFile(screenshotFile, new File("screenshots/test_" + timestamp + ".png"));
} catch (Exception e) {
System.out.println("截图失败");
} finally {
if (driver != null) {
driver.quit();
}
}
}
}
src/test/resources/testng.xml
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Herokuapp Test Suite">
<test name="Login and Search Test">
<classes>
<class name="com.example.tests.HerokuappTest"/>
</classes>
</test>
</suite>
总结与下一步
这份教程涵盖了 Selenium with Java 的核心知识和最佳实践,从环境搭建到 POM 设计模式,再到数据驱动测试,你已经具备了构建健壮、可维护的自动化测试套件的基础。
下一步可以学习的内容:
- Selenium Grid: 学习如何在不同机器和浏览器上并行执行测试,大幅提升测试效率。
- 持续集成/持续部署: 将你的自动化测试集成到 Jenkins, GitLab CI, GitHub Actions 等工具中,实现代码提交后自动触发测试。
- 高级框架: 探索更高级的测试框架,如 Cucumber (BDD 行为驱动开发)。
- API 测试: 学习使用 Rest-Assured 等工具进行 API 测试,因为现代应用的前后端通常是分离的。
祝你学习愉快!
