1. 引言
本文将基于前一篇教程,继续深入探讨如何通过页面对象模式(Page Object Pattern)优化 Selenium/WebDriver 测试方案。这种模式能有效提升测试代码的可维护性和可读性,是自动化测试中的最佳实践之一。
2. 添加 Selenium 依赖
首先在项目中引入一个能简化断言编写的依赖:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
最新版本可在 Maven 中央仓库 查询。
2.1. 补充工具方法
前文用到的几个实用方法这里会继续使用:
页面导航方法:封装浏览器跳转逻辑
public void navigateTo(String url) { driver.navigate().to(url); }
元素点击方法:统一处理点击操作
public void clickElement(WebElement element) { element.click(); }
3. 页面对象模式详解
Selenium 提供了强大的底层 API 直接操作 HTML 元素,但随着测试复杂度增加,直接操作 DOM 元素会带来明显问题:
❌ 代码脆弱:UI 微小改动可能导致测试失败
❌ 维护困难:元素定位逻辑散落在各处
❌ 可读性差:测试意图被技术细节淹没
解决方案:通过页面对象模式封装底层细节,暴露高层 API。该模式核心思想是:
✅ 将页面/组件抽象为对象
✅ 封装元素定位和交互逻辑
✅ 提供符合用户操作语义的方法名(如 clickButton()
)
下面创建首页的页面对象示例:
public class BaeldungHomePage {
private SeleniumConfig config;
@FindBy(css = ".nav--logo_mobile")
private WebElement title;
@FindBy(css = ".menu-start-here > a")
private WebElement startHere;
// ...
public StartHerePage clickOnStartHere() {
config.clickElement(startHere);
StartHerePage startHerePage = new StartHerePage(config);
PageFactory.initElements(config.getDriver(), startHerePage);
return startHerePage;
}
}
关键点解析:
@FindBy
注解预加载元素(比By
API 更简洁)- 方法返回新页面对象,实现操作链式调用
- 方法名体现业务语义(如
clickOnStartHere()
而非clickElement()
)
对应的目标页面对象:
public class StartHerePage {
// 包含 SeleniumConfig 属性
@FindBy(css = ".page-title")
private WebElement title;
// 构造方法
public String getPageTitle() {
return title.getText();
}
}
测试用例示例:
@Test
public void givenHomePage_whenNavigate_thenShouldBeInStartHere() {
homePage.navigate();
StartHerePage startHerePage = homePage.clickOnStartHere();
assertThat(startHerePage.getPageTitle(), is("Start Here"));
}
测试流程清晰可见:
- 导航到首页
- 点击"Start Here"按钮
- 验证目标页面标题
3.1. 关注点分离进阶
更彻底的解耦方案:将元素定义和操作逻辑分离到两个类:
元素定义类(仅声明元素):
public class BaeldungAboutPage {
@FindBy(css = ".page-header > h1")
public static WebElement title;
}
操作逻辑类(封装行为):
public class BaeldungAbout {
private SeleniumConfig config;
public BaeldungAbout(SeleniumConfig config) {
this.config = config;
PageFactory.initElements(config.getDriver(), BaeldungAboutPage.class);
}
// 导航和获取标题方法
}
⚠️ 注意:若使用 By
而非注解,应在元素类添加私有构造方法防止实例化。
测试用例:
@Test
public void givenAboutPage_whenNavigate_thenTitleMatch() {
about.navigateTo();
assertThat(about.getPageTitle(), is("About Baeldung"));
}
优势:
- 元素定位与操作逻辑完全解耦
- 测试代码更接近业务描述
- UI 变更只需修改元素定义类
4. 总结
本文通过实际案例展示了页面对象模式在 Selenium 测试中的核心价值:
✅ 提升可维护性:UI 变更影响范围最小化
✅ 增强可读性:测试用例聚焦业务流程
✅ 促进复用:页面对象可在多个测试中共享
完整实现代码已上传至 GitHub,这是一个 Maven 项目,可直接导入运行。建议结合实际项目尝试该模式,踩坑后你会体会到它的强大之处。