You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java UI自动化测试(POM模式)中合理运用组合模式?

Java UI自动化测试中组合模式的最佳实践

初始问题:重复实现Modal相关逻辑

多个Page类都包含相同的Modal组件操作,导致代码重复:

class PageA {
  private static final String CHECKBOX_ON_MODAL = "//div[@id='checkbox']";

  public void selectCheckBox() {
    // 选择复选框的实现逻辑
  }
}
class PageB {
  private static final String CHECKBOX_ON_MODAL = "//div[@id='checkbox']";

  public void selectCheckBox() {
    // 选择复选框的实现逻辑
  }
}
class PageC {
  private static final String CHECKBOX_ON_MODAL = "//div[@id='checkbox']";

  public void selectCheckBox() {
    // 选择复选框的实现逻辑
  }
}

组合模式尝试:复用Modal组件

为了消除重复,提取独立的Modal类,并注入到各个Page类中:

class Modal {
  private static final String CHECKBOX_ON_MODAL = "//div[@id='checkbox']";

  public void selectCheckBox() {
    // 选择复选框的实现逻辑
  }
}
class PageA {
  private Modal modal;

  public PageA() {
    modal = new Modal();
  }

  public Modal getModal() {
    return modal;
  }
}

class PageB {
  private Modal modal;

  public PageB() {
    modal = new Modal();
  }

  public Modal getModal() {
    return modal;
  }
}

class PageC {
  private Modal modal;

  public PageC() {
    modal = new Modal();
  }

  public Modal getModal() {
    return modal;
  }
}

测试代码调用方式:

public final class TestExample {

  @Test
  public void test1 () {
    PageA pageA = new PageA();
    Modal modal = pageA.getModal();
    modal.selectCheckBox();
  }

  @Test
  public void test2 () {
    PageB pageB = new PageB();
    Modal modal2 = pageB.getModal();
    modal2.selectCheckBox();
  }

  @Test
  public void test3 () {
    PageC pageC= new PageC();
    Modal modal3 = pageC.getModal();
    modal3.selectCheckBox();
  }
}

核心问题:Modal组件状态随页面变化

同一个Modal的复选框在不同页面表现不同:

  • PageA中:可见且可操作
  • PageB中:可见但不可操作
  • PageC中:完全不可见

需要在编译时限制对Modal组件的操作,避免在不允许的页面调用无效方法。

现有方案的局限

  • 方案1:在Page类中单独实现checkbox操作,直接失去组合模式的复用价值
  • 方案2:为不同页面创建专属Modal实现类或接口,会导致类爆炸,复用性下降
  • 方案3:向测试方法传入校验器参数,代码冗余且不够简洁

简洁高效的解决办法:基于能力的接口分层+泛型约束

步骤1:定义不同能力的Modal接口

根据组件的可操作状态,拆分出不同层级的接口:

// 基础Modal接口,仅定义通用行为(比如关闭Modal)
interface BaseModal {
  void close();
}

// 包含可查看复选框的Modal接口
interface CheckboxViewableModal extends BaseModal {
  boolean isCheckboxVisible();
}

// 包含可操作复选框的Modal接口
interface CheckboxOperableModal extends CheckboxViewableModal {
  void selectCheckBox();
}

步骤2:实现通用Modal类,实现所有接口

复用核心逻辑,同时实现所有能力接口:

class GenericModal implements CheckboxOperableModal {
  private static final String CHECKBOX_ON_MODAL = "//div[@id='checkbox']";

  @Override
  public void close() {
    // 关闭Modal的实现
  }

  @Override
  public boolean isCheckboxVisible() {
    // 校验复选框可见性的实现
  }

  @Override
  public void selectCheckBox() {
    // 选择复选框的实现,可提前加入状态校验(比如先判断是否可操作)
    if (!isCheckboxVisible() || !isCheckboxEnabled()) {
      throw new IllegalStateException("Checkbox is not operable on current page");
    }
    // 执行选择逻辑
  }

  private boolean isCheckboxEnabled() {
    // 校验复选框可用性的实现
  }
}

步骤3:在Page类中通过泛型约束暴露对应能力的Modal

每个Page类根据自身Modal的可用能力,返回对应层级的接口:

class PageA {
  private CheckboxOperableModal modal;

  public PageA() {
    modal = new GenericModal();
  }

  public CheckboxOperableModal getModal() {
    return modal;
  }
}

class PageB {
  private CheckboxViewableModal modal;

  public PageB() {
    modal = new GenericModal();
  }

  public CheckboxViewableModal getModal() {
    return modal;
  }
}

class PageC {
  private BaseModal modal;

  public PageC() {
    modal = new GenericModal();
  }

  public BaseModal getModal() {
    return modal;
  }
}

步骤4:测试代码中的编译时约束

此时在编译阶段就会限制操作:

public final class TestExample {

  @Test
  public void test1 () {
    PageA pageA = new PageA();
    // PageA的Modal支持selectCheckBox(),编译通过
    pageA.getModal().selectCheckBox();
  }

  @Test
  public void test2 () {
    PageB pageB = new PageB();
    // PageB的Modal仅支持查看,调用selectCheckBox()会直接编译报错
    pageB.getModal().isCheckboxVisible(); // 合法操作
    // pageB.getModal().selectCheckBox(); // 编译错误
  }

  @Test
  public void test3 () {
    PageC pageC= new PageC();
    // PageC的Modal仅支持关闭,调用checkbox相关方法都会编译报错
    pageC.getModal().close(); // 合法操作
    // pageC.getModal().isCheckboxVisible(); // 编译错误
  }
}

方案优势

  1. 完全保留组合模式的复用性:核心Modal逻辑仅在GenericModal中实现一次
  2. 编译时约束操作:通过接口分层和泛型,直接在编码阶段避免无效调用
  3. 扩展性强:新增页面或Modal能力时,只需新增接口或调整Page类的返回类型即可
  4. 代码简洁:无需创建大量专属Modal类,也不需要额外校验参数

内容的提问来源于stack exchange,提问作者Max Sudik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:25:35