Protractor JS处理大型重复测试任务的最优设计模式
多步重复测试任务的最优实现方案
针对你提到的changeDealer()这类高频复用的多步业务操作,推荐用原子操作拆分+高层业务工作流封装的设计模式,结合你现有的页面对象(PO)架构适配即可,核心设计思路如下:
1. 先拆分原子操作,消除重复代码
你当前changeDealer()的两个分支里80%的步骤完全重复,先把通用步骤拆成仅负责单一动作的原子方法,按所属页面放在对应PO文件中:
- 头部操作相关方法放在
DealerHeader类中:expandHeader()、openDealerModal() - 经销商定位页相关方法放在
Locators类中:navigateToLocatorPage()、searchDealerByZip(zipCode?: string)、pickRandomDealer()、confirmDealerChange(isDealerSet: boolean)
示例代码:
// locators.po.ts 补充原子方法 async searchDealerByZip(zipCode = '10001') { await waitToBeDisplayed(this.zipInput); await this.zipInput.sendKeys(zipCode, Key.ENTER); await waitToBeDisplayed(this.dealerList); } async pickRandomDealer() { const dealerList = await this.dealerListItems; const randomIndex = Math.floor(Math.random() * dealerList.length); await click(dealerList[randomIndex].$('.detail-btn')); await waitToBeDisplayed(this.confirmDealerBtn); }
2. 封装高层业务工作流方法
把原子方法按业务逻辑串成changeDealer()方法,放在和业务最相关的PO类(这里是Locators类),支持可选入参适配不同测试场景,同时加前置状态校验减少冗余操作:
// locators.po.ts 封装后的changeDealer async changeDealer(targetZip?: string, targetDealerId?: string) { // 前置校验:如果已经是目标经销商,直接返回,跳过全流程 const currentDealer = await getCurrentDealerId(); if (targetDealerId && currentDealer === targetDealerId) return; // 通用前置步骤 const dh = new DealerHeader(); await dh.expandHeader(); await dh.openDealerModal(); await this.navigateToLocatorPage(); await browser.executeScript('window.scrollTo(0, document.body.scrollHeight)'); // 支持自定义邮编/默认随机邮编 await this.searchDealerByZip(targetZip ?? getRandomTestZip()); // 支持指定经销商/默认随机选 targetDealerId ? await this.pickDealerById(targetDealerId) : await this.pickRandomDealer(); // 分支逻辑仅保留差异部分 const isDealerPreSet = !!currentDealer; await this.confirmDealerChange(isDealerPreSet); // 可选加后置校验:确保切换成功 await waitForDealerIdChange(currentDealer); }
3. 测试用例层仅调用高层方法
测试用例文件中不要散落操作步骤,只调用封装好的业务方法,仅保留断言逻辑:
// header.test.ts 简化后的用例 it('Dealer Header Display', async() => { const dh: DealerHeader = new DealerHeader(); const loc: Locators = new Locators(); const dealerHeaderPrimaryDealerName = await dh.dealerHeaderPrimaryDealerName(); if (!await dealerHeaderPrimaryDealerName.isPresent()) { await loc.changeDealer(); // 直接调用封装好的方法即可 } await waitToBeDisplayed(dealerHeaderPrimaryDealerName); await expect(dealerHeaderPrimaryDealerName).toBeDisplayed(); // 其余断言逻辑保持不变 });
方案优势
- 维护成本低:业务流程改动时,仅需要修改对应原子方法或工作流的组装逻辑,不需要逐个修改所有用到切换经销商操作的测试用例
- 复用性强:支持自定义入参适配不同测试场景,比如需要测试指定区域经销商的用例,直接传入对应邮编即可
- 稳定性高:所有等待、异常处理逻辑都封装在方法内部,避免不同用例写操作步骤时漏加等待导致的偶现失败
- 可读性好:测试用例逻辑清晰,看方法名就能知道做了什么操作,不需要读大段步骤代码
内容的提问来源于stack exchange,提问作者MaylorTaylor
相关产品推荐
相关产品推荐

