
1. 引言与背景
在 Web 应用测试中,表格数据的排序功能是常见的测试点之一。用户通常期望点击列标题后,表格数据能按照该列的数值或字母顺序正确排列。手动验证大量数据不仅耗时且易出错,因此,使用 Selenium 自动化验证表格排序功能变得尤为重要。本教程将以一个具体的“金额”列为例,演示如何使用 Java 和 Selenium 验证表格数据的升序和降序排列。
2. 环境准备
在开始之前,请确保您的开发环境已配置以下组件:
- Java Development Kit (JDK):版本 8 或更高。
- Maven 或 Gradle:用于项目管理和依赖管理。
- Selenium WebDriver:核心自动化库。
- JUnit 或 TestNG:测试框架。
- ChromeDriver:或其他浏览器驱动(如 GeckoDriver for Firefox),与您的浏览器版本匹配。
Maven pom.xml 依赖示例:
org.seleniumhq.selenium selenium-java 4.1.2 junit junit 4.13.2 test io.github.bonigarcia webdrivermanager 5.0.3 test
3. 核心验证步骤
验证表格数据排序通常涉及以下几个关键步骤:
立即学习“Java免费学习笔记(深入)”;
3.1 初始化 WebDriver 并导航
首先,需要设置 WebDriver 并导航到包含目标表格的网页。这通常包括浏览器启动、最大化窗口以及登录等操作。
3.2 提取原始数据
在执行任何排序操作之前,我们需要获取表格中目标列的当前数据。这些数据将作为我们生成预期排序结果的基准。
3.3 数据清洗与类型转换
从网页元素中提取的文本数据通常包含货币符号、逗号、空格等非数字字符。为了能够进行数值排序,必须对这些字符串进行清洗,并将其转换为可比较的数值类型(如 Double)。
3.4 准备预期排序数据
基于清洗后的原始数值列表,我们可以使用 Java 的 Collections.sort() 方法生成一个预期升序排列的列表。如果需要验证降序,则可以对升序列表进行反转。
3.5 触发 UI 排序操作
通过 Selenium 定位并点击表格列的标题元素,以触发网页的内置排序功能。
3.6 提取实际排序数据
点击排序按钮后,再次从表格中提取目标列的文本数据,并进行相同的清洗和类型转换,得到实际的排序结果。
3.7 执行断言验证
最后,使用断言(如 Assert.assertEquals())比较实际排序结果列表与预期排序结果列表。如果两者完全相同,则表示排序功能正常。
4. 示例代码:验证“金额”列排序
以下是一个完整的 Java Selenium JUnit 测试示例,用于验证指定网页上“金额”列的升序和降序排序功能。
package com.example.seleniumtests;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class TableSortingVerification {
private static WebDriver driver;
private static WebDriverWait wait;
// 辅助方法:提取并清洗金额数据
private List extractAndCleanAmountData() {
// 定位所有金额列的span元素
List amountElements = driver.findElements(By.xpath("//table[@id='transactionsTable']/tbody/tr/td/span"));
List cleanedAmounts = new ArrayList<>();
for (WebElement element : amountElements) {
String text = element.getText();
// 清除货币符号 "USD", 逗号 ",", 空格 " "
String cleanedText = text.replaceAll("USD", "").replaceAll(",", "").trim();
try {
// 转换为 Double 类型
cleanedAmounts.add(Double.parseDouble(cleanedText));
} catch (NumberFormatException e) {
System.err.println("无法解析金额: " + text + " - " + e.getMessage());
// 根据需求处理错误,例如跳过或抛出异常
}
}
return cleanedAmounts;
}
@BeforeClass
public static void setup() {
// 自动管理 ChromeDriver (推荐使用 WebDriverManager)
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.manage().window().maximize();
wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // 显式等待
// 导航到登录页面并登录
String loginUrl = "https://sakshingp.github.io/assignment/login.html";
driver.get(loginUrl);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username"))).sendKeys("Lakshay");
driver.findElement(By.id("password")).sendKeys("Wingify");
driver.findElement(By.id("log-in")).click();
// 等待登录成功并跳转到主页
wait.until(ExpectedConditions.urlContains("home.html"));
System.out.println("成功登录并进入主页.");
}
@Test
public void testAmountColumnSorting() {
System.out.println("开始验证金额列排序...");
// 1. 提取原始(未排序)金额数据
List initialAmounts = extractAndCleanAmountData();
System.out.println("原始金额数据: " + initialAmounts);
// 2. 准备预期升序数据
List expectedAscendingAmounts = new ArrayList<>(initialAmounts);
Collections.sort(expectedAscendingAmounts); // 默认升序
System.out.println("预期升序数据: " + expectedAscendingAmounts);
// 3. 触发 UI 升序排序操作
WebElement amountHeader = driver.findElement(By.id("amount"));
amountHeader.click(); // 第一次点击通常是升序
// 4. 提取实际升序排序后的数据
// 等待表格内容更新,这里可以根据实际页面加载情况调整等待策略
// 简单等待一段时间,或者等待某个元素状态变化
wait.until(ExpectedConditions.stalenessOf(amountHeader)); // 假设点击后页面有刷新或部分更新
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//table[@id='transactionsTable']/tbody/tr/td/span"))); // 确保元素可见
List actualAscendingAmounts = extractAndCleanAmountData();
System.out.println("实际升序数据: " + actualAscendingAmounts);
// 5. 验证升序排序
Assert.assertEquals("金额列升序排序验证失败!", expectedAscendingAmounts, actualAscendingAmounts);
System.out.println("金额列升序排序验证成功!");
// --- 验证降序排序(可选) ---
System.out.println("\n开始验证金额列降序排序...");
// 1. 准备预期降序数据
List expectedDescendingAmounts = new ArrayList<>(expectedAscendingAmounts);
Collections.reverse(expectedDescendingAmounts); // 反转升序列表得到降序
System.out.println("预期降序数据: " + expectedDescendingAmounts);
// 2. 触发 UI 降序排序操作 (再次点击通常是降序)
amountHeader.click();
// 3. 提取实际降序排序后的数据
wait.until(ExpectedConditions.stalenessOf(amountHeader)); // 假设点击后页面有刷新或部分更新
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//table[@id='transactionsTable']/tbody/tr/td/span"))); // 确保元素可见
List actualDescendingAmounts = extractAndCleanAmountData();
System.out.println("实际降序数据: " + actualDescendingAmounts);
// 4. 验证降序排序
Assert.assertEquals("金额列降序排序验证失败!", expectedDescendingAmounts, actualDescendingAmounts);
System.out.println("金额列降序排序验证成功!");
}
@AfterClass
public static void tearDown() {
if (driver != null) {
driver.quit();
System.out.println("浏览器已关闭.");
}
}
} 5. 注意事项与最佳实践
- 等待策略:在 Selenium 自动化中,等待是至关重要的。本示例使用了 WebDriverWait 显式等待,确保元素可见或页面加载完成。避免使用 Thread.sleep(),因为它会导致测试不稳定和效率低下。
- 数据清洗的健壮性:replaceAll() 方法能够很好地处理字符串中的特定字符。如果金额格式更复杂(例如,包含多种货币符号、负号位置不同等),可能需要更复杂的正则表达式或自定义解析逻辑。
- 异常处理:在将字符串转换为 Double 时,务必捕获 NumberFormatException。这可以防止因页面上出现非数字文本而导致测试崩溃。
- 定位器策略:本示例使用了 XPath (//table[@id='transactionsTable']/tbody/tr/td/span) 来定位金额列。选择稳定且具有唯一性的定位器(如 ID、CSS Selector 或更具体的 XPath)对于测试的健壮性至关重要。避免使用过于脆弱的定位器,如绝对 XPath。
- 升序/降序逻辑:通常,第一次点击列标题是升序,第二次点击是降序。如果页面行为不同,需要调整测试逻辑。
- 动态表格内容:如果表格内容是动态加载的(例如,通过 AJAX),确保在提取数据前有足够的等待时间,以确保所有数据都已加载并呈现在 DOM 中。
- 代码可读性与复用:将数据提取和清洗逻辑封装到单独的辅助方法中(如 extractAndCleanAmountData()),可以提高代码的可读性和复用性。
6. 总结
通过本教程,您应该掌握了如何使用 Java 和 Selenium WebDriver 自动化验证网页表格的排序功能。核心在于正确地提取、清洗和转换数据,然后与预期排序结果进行比较。这种自动化测试方法不仅提高了测试效率,也大大增强了测试的准确性和可靠性,确保了 Web 应用数据展示的正确性。










