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"));
}

测试流程清晰可见:

  1. 导航到首页
  2. 点击"Start Here"按钮
  3. 验证目标页面标题

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 项目,可直接导入运行。建议结合实际项目尝试该模式,踩坑后你会体会到它的强大之处。


原始标题:Selenium/WebDriver and the Page Object Pattern

« 上一篇: Quartz调度框架详解
» 下一篇: Java Weekly, 第182期