杰瑞科技汇

selenium 教程 java

Selenium with Java 完整教程

目录

  1. 第一部分:环境准备

    • 1 前置条件
    • 2 安装和配置 IDE (IntelliJ IDEA)
    • 3 创建 Maven 项目
    • 4 添加 Selenium 依赖
    • 5 下载浏览器驱动
  2. 第二部分:Selenium 核心概念与 API

    • 1 Selenium WebDriver 架构简介
    • 2 第一个自动化脚本:打开和关闭浏览器
    • 3 元素定位策略
    • 4 浏览器操作
    • 5 元素交互
    • 6 等待策略
    • 7 下拉框处理
    • 8 弹窗处理
    • 9 多窗口/标签页处理
    • 10 JavaScript 执行器
    • 11 截图
  3. 第三部分:高级主题与最佳实践

    • 1 Page Object Model (POM) 设计模式
    • 2 数据驱动测试 (使用 TestNG 和 DataProvider)
    • 3 集成 TestNG 框架
    • 4 使用 Selenium Grid 进行分布式测试
  4. 第四部分:实战项目示例

    • 1 项目目标
    • 2 项目结构
    • 3 代码实现

第一部分:环境准备

1 前置条件

在开始之前,请确保你已经安装了以下软件:

  1. Java Development Kit (JDK): 建议使用 JDK 8 或更高版本,你可以从 Oracle 官网 下载。
  2. 集成开发环境: 推荐使用 IntelliJ IDEA (社区版免费) 或 Eclipse,本教程以 IntelliJ IDEA 为例。
  3. 浏览器: 本教程使用 Google Chrome

2 安装和配置 IDE (IntelliJ IDEA)

  1. 下载并安装 IntelliJ IDEA Community Edition。
  2. 启动 IDE,接受许可协议。
  3. 你可以导入之前的设置或选择 "Do not import settings"。

3 创建 Maven 项目

Maven 是一个项目管理和构建自动化工具,可以非常方便地管理项目依赖(Selenium 库)。

  1. 在 IntelliJ IDEA 中,点击 File -> New -> Project
  2. 在左侧面板选择 Maven
  3. 确保 Create from archetype 选项是未选中的状态,然后点击 Next
  4. 填写 GroupId (通常为你的组织或个人域名,如 com.example) 和 ArtifactId (项目名,如 selenium-tutorial),点击 Next
  5. 选择你的 Maven 设置(通常使用默认即可),点击 Next
  6. 选择项目存放位置,点击 Finish
  7. 等待 Maven 下载完项目模板和依赖后,你的项目结构就创建好了。

4 添加 Selenium 依赖

我们需要在 pom.xml 文件中添加 Selenium WebDriver 的依赖。

  1. 打开 pom.xml 文件。
  2. <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>
  1. IntelliJ IDEA 会自动识别并下载这些依赖,你也可以点击 Maven 窗口(右侧)中的 Reload All Maven Projects 按钮手动刷新。

5 下载浏览器驱动

Selenium 本身不控制浏览器,它通过一个叫 WebDriver 的库与浏览器进行通信,WebDriver 是一个与浏览器绑定的可执行程序。

Chrome 为例:

  1. 确定你的 Chrome 浏览器版本:在 Chrome 地址栏输入 chrome://version/ 查看。
  2. 下载对应版本的 WebDriver
    • 访问 Chrome for Testing availability
    • 找到与你浏览器版本最接近的 chromedriver 版本。
    • 下载对应你操作系统的 zip 包(如 win32, mac-x64, linux64)。
  3. 配置 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

有三种等待方式:

  1. 硬性等待 (不推荐): Thread.sleep(5000); 让脚本暂停固定时间,这会大大降低测试效率,不推荐使用。

  2. 隐式等待: 在查找元素时,如果找不到,WebDriver 会等待一个指定的时间再去查找。

    // 设置隐式等待,全局有效,通常在创建 driver 后设置一次
    driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
    • 缺点: 它会为 findElementfindElements 的所有调用设置等待,如果你在等待一个元素 A,但元素 B 先出现,它也会浪费时间等待 A,即使你并不关心 A。
  3. 显式等待 (强烈推荐): 针对某个特定的元素,设置一个条件,如果条件在指定时间内满足,就立即继续执行;如果超时,则抛出异常。

    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 是一个强大的测试框架,提供了测试分组、依赖、参数化、并行执行等丰富功能。

  1. 确保 pom.xml 中有 TestNG 依赖 (见 1.4)。
  2. 创建 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>
  3. 运行测试: 在 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 项目目标

自动化测试一个简单的用户登录和搜索功能。

  1. 打开 https://the-internet.herokuapp.com/login
  2. 使用不同的用户名和密码进行登录测试(成功和失败场景)。
  3. 登录成功后,导航到 https://the-internet.herokuapp.com/
  4. 在搜索框中输入 "ab"。
  5. 验证搜索结果中是否包含 "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 测试,因为现代应用的前后端通常是分离的。

祝你学习愉快!

分享:
扫描分享到社交APP
上一篇
下一篇