如何在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(); // 编译错误 } }
方案优势
- 完全保留组合模式的复用性:核心Modal逻辑仅在
GenericModal中实现一次 - 编译时约束操作:通过接口分层和泛型,直接在编码阶段避免无效调用
- 扩展性强:新增页面或Modal能力时,只需新增接口或调整Page类的返回类型即可
- 代码简洁:无需创建大量专属Modal类,也不需要额外校验参数
内容的提问来源于stack exchange,提问作者Max Sudik
相关产品推荐
相关产品推荐

