总结:WEB UI自动化测试一般采用 POP(面向页面编程),自动化测试框架分三层,有时如果页面如果太多,不好管理,可以面向控件编程,即把控件当作页面,毕竟控件是有限的,所以封装页面的代码量会少很多,两种方式各有优劣。如果页面比较少的,建议可以全部封装为页面对象;如果页面比较多,而且跳转复杂,建议使用两者结合的方式,一级页面,二级页面封装,三级以上页面,就不需要封装,使用控件对象完成页面操作。利用封装好的页面对象/控件对象,再进一步完成业务关键字封装,比如登录,注册,添加商品,支付等等操作,这样有个好处就是需求变动,业务流程调整,或者添加流程等,只需要封装新的流程,重组用例,维护工作量会减少很多。这样的三层结构非常清晰,第一层页面对象封装层只需要关注维护页面元素对象,第二层业务封装层只需要关注产品的业务流程拆分,第三层用例层只需要关注用例的流程组合以及测试数据,具体架构参考下图:
下面附上部分代码,有不对的地方请指正。
接口,定义基类页面的方法,可能不全,需要的可以继续补充
1 import org.openqa.selenium.WebElement; 2 3 interface BasePage { 4 WebElement findElement(String loc); 5 6 void sendKeys(String loc, String var1); 7 8 void click(String loc); 9 10 void submit(String loc); 11 12 void switchToFrame(String loc); 13 14 void switchToParentFrame(); 15 16 void closeAlert(); 17 18 void acceptAlert(); 19 20 String getAlertText(); 21 22 void moveToElement(String loc); 23 24 void doubleClick(String loc); 25 26 void contextClick(String loc); 27 28 void dragAndDrop(String source, String target); 29 30 void closeBrowser(); 31 32 String getTitle(); 33 34 String getUrl(); 35 36 void maxBrowser(); 37 }
基类实现的抽象类,其他的页面继承该类再个性化实现即可:
1 import com.uitest.control.by.LocationUtil; 2 import org.openqa.selenium.WebDriver; 3 import org.openqa.selenium.WebElement; 4 import org.openqa.selenium.interactions.Actions; 5 6 import java.util.concurrent.TimeUnit; 7 8 public abstract class BasePageImpl implements BasePage { 9 protected final WebDriver driver; 10 private static final long timeOutInSeconds = 10; 11 12 BasePageImpl(WebDriver driver, String url) { 13 this.driver = driver; 14 this.driver.manage().timeouts().implicitlyWait(timeOutInSeconds, TimeUnit.SECONDS); 15 this.driver.get(url); 16 } 17 18 BasePageImpl(WebDriver driver) { 19 this.driver = driver; 20 this.driver.manage().timeouts().implicitlyWait(timeOutInSeconds, TimeUnit.SECONDS); 21 } 22 23 public WebElement findElement(String loc) { 24 return driver.findElement(LocationUtil.getLocation(loc)); 25 } 26 27 public void sendKeys(String loc, String var1) { 28 findElement(loc).sendKeys(var1); 29 } 30 31 public void click(String loc) { 32 findElement(loc).click(); 33 } 34 35 public void submit(String loc) { 36 findElement(loc).submit(); 37 } 38 39 public void switchToFrame(String loc) { 40 driver.switchTo().frame(findElement(loc)); 41 } 42 43 public void switchToParentFrame() { 44 driver.switchTo().parentFrame(); 45 } 46 47 public void closeAlert() { 48 driver.switchTo().alert().dismiss(); 49 } 50 51 public void acceptAlert() { 52 driver.switchTo().alert().accept(); 53 } 54 55 public String getAlertText() { 56 return driver.switchTo().alert().getText(); 57 } 58 59 public void moveToElement(String loc) { 60 new Actions(driver).moveToElement(findElement(loc)).perform(); 61 } 62 63 public void doubleClick(String loc) { 64 new Actions(driver).doubleClick(findElement(loc)).perform(); 65 } 66 67 public void contextClick(String loc) { 68 new Actions(driver).contextClick(findElement(loc)).perform(); 69 } 70 71 public void dragAndDrop(String source, String target) { 72 new Actions(driver).dragAndDrop(findElement(source), findElement(target)).perform(); 73 } 74 75 public void closeBrowser() { 76 driver.close(); 77 } 78 79 public String getTitle() { 80 return driver.getTitle(); 81 } 82 83 public String getUrl() { 84 return driver.getCurrentUrl(); 85 } 86 87 public void maxBrowser() { 88 driver.manage().window().maximize(); 89 } 90 }
工具类:
1 import org.openqa.selenium.By; 2 3 import java.util.Arrays; 4 import java.util.List; 5 6 public class LocationUtil { 7 /** 8 * 定位信息,比如id=kw 9 * @param var 格式xpath=//*[@id="kw"] 10 * @return org.openqa.selenium.By 11 */ 12 public static By getLocation (String var) { 13 List list = Arrays.asList(var.split("=", 2)); 14 if (list.size() < 2 || "".equals(list.get(1))) { 15 return null; 16 } 17 String loc = String.valueOf(list.get(1)); 18 switch (ByType.valueOf(list.get(0).toString().toUpperCase())) { 19 case ID: 20 return By.id(loc); 21 case NAME: 22 return By.name(loc); 23 case XPATH: 24 return By.xpath(loc); 25 case CSS: 26 return By.cssSelector(loc); 27 case TAG: 28 return By.tagName(loc); 29 case CLASS: 30 return By.className(loc); 31 case LINKTEXT: 32 return By.linkText(loc); 33 case PARTIALLINKTEXT: 34 return By.partialLinkText(loc); 35 default: 36 return null; 37 } 38 } 39 }