之前介绍了Page Object的概念及基本使用(这里), 虽然实现了页与页的分离, 测试与页的分离, 但有些时候可能只是改个别元素的id什么的, 不需要改动更多, PageFactory(Selenium wiki)就是Selenium用来帮助更简单搞笑实现Page Object的一个工具类.
本文结合上篇给出使用了PageFactory和没使用的区别:
PageFactory: LoginPage.java:
1 import org.openqa.selenium.WebDriver; 2 import org.openqa.selenium.WebElement; 3 import org.openqa.selenium.support.CacheLookup; 4 import org.openqa.selenium.support.FindBy; 5 //需要导入PageFactory包 6 import org.openqa.selenium.support.PageFactory; 7 import java.util.List; 8 import java.util.concurrent.TimeUnit; 9 10 public class LoginPage { 11 WebDriver driver; 12 13 //关于元素的查找全部放page最前面, 后期如有UI修改很方便 14 //@FindBy 是有一个特性是使用的时候才会调用实际上的findElement 15 //如果确定此元素在当前页面不再改变, 可以加上@CacheLookup, 第一次找过此元素后不会再次查找 16 @FindBy(id = "lbNormal") 17 @CacheLookup 18 private WebElement accoutLogin; 19 @FindBy(tagName = "iframe") 20 private List<WebElement> iframes; 21 @FindBy(name = "email") 22 private WebElement loginEmail; 23 @FindBy(name = "password") 24 private WebElement loginPassword; 25 @FindBy(id = "dologin") 26 private WebElement loginButton; 27 28 public LoginPage(WebDriver driver) { 29 this.driver = driver; 30 } 31 32 public HomePage login(String user, String pwd) { 33 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 34 accoutLogin.click(); 35 String id = iframes.get(0).getAttribute("id"); 36 if (id != null) { 37 driver.switchTo().frame(id); 38 } 39 loginEmail.sendKeys(user); 40 loginPassword.sendKeys(pwd); 41 loginButton.click(); 42 driver.switchTo().defaultContent(); 43 driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); 44 45 //使用PageFactory传递driver实例初始化@FindBy的元素并实例化下一个被跳转的页面 46 HomePage homePage = new HomePage(); 47 PageFactory.initElements(driver, homePage); 48 return homePage; 49 } 50 }
PageFactory: LoginTest.java
1 import org.openqa.selenium.WebDriver; 2 import org.openqa.selenium.support.PageFactory; 3 import org.testng.Assert; 4 import simple.com.faye.selenium.pages.HomePage; 5 import simple.com.faye.selenium.pages.LoginPage; 6 import simple.com.faye.selenium.utils.SeleniumInit; 7 8 public class LoginTest { 9 public static void main(String[] args) { 10 SeleniumInit seleniumInit = new SeleniumInit(); 11 WebDriver driver = seleniumInit.getFFDriver(); 12 String URL = "https://mail.163.com/"; 13 String user = "邮箱"; 14 String pwd = "密码"; 15 try { 16 driver.get(URL); 17 LoginPage loginPage = new LoginPage(driver); 18 //注意要初始化LoginPage页面(HomePage不需要是因为login方法已经初始化了) 19 PageFactory.initElements(driver, loginPage); 20 HomePage homePage = loginPage.login(user, pwd); 21 Assert.assertTrue(homePage.idExists(), "login failed"); 22 } catch (Exception e) { 23 e.printStackTrace(); 24 } finally { 25 driver.quit(); 26 } 27 } 28 }
LoginPage.java对比:
1 class LoginPagePageObejectOnly { 2 WebDriver driver; 3 4 public HomePage loginOperation(String user, String pwd) { 5 // 进入frame略, 没PageFactory若有改动需得进入所有使用此元素的方法修改 6 WebElement loginEmail = driver.findElement(By.name("email")); 7 loginEmail.sendKeys(user); 8 9 //直接返回到新页面,不需要调用PageFactory.initElements, 但要传driver实例 10 return new HomePage(driver); 11 } 12 } 13 14 class LoginPageWithPageFactory { 15 WebDriver driver; 16 //若有改动仅需改动此一处则其他所有使用此元素的方法都无需修改 17 //若加上@CacheLookup, 第一次找过此元素后不会再次查找 18 @FindBy(name = "email") 19 private WebElement loginEmail; 20 21 public HomePage loginOperation(String user, String pwd) { 22 // 进入frame略, 使用时去调用findElement 23 loginEmail.sendKeys(user); 24 25 //使用PageFactory传递driver实例初始化@FindBy的元素并实例化下一个被跳转的页面 26 HomePage homePage = new HomePage(); 27 PageFactory.initElements(driver, homePage); 28 return homePage; 29 } 30 }
以上代码可以看到使用区别以及使用方法, PageFactory还有@FindBys用以查找List<WebElement>, 以及类似以下方式的使用, 不过个人不推荐, 原因是此种方法仅适用于find by id 和 name, 且元素变量名需和页面元素的查找值一样, 还是一改全得改, 不划算:
1 public class HomePage { 2 //先把元素id 或 name定义上 3 private WebElement spnUid; 4 5 public boolean idExists() { 6 //使用时先执行 driver.findElement(By.id("spnUid"))找元素, 7 //若没有则执行 driver.findElement(By.name("spnUid"))找元素 8 //再没有则会抛 NoSuchElementException, 相较@FindBy可以使用findByElement的所有常用方式来说不够用 9 System.out.println(spnUid.getText()); 10 return spnUid.isDisplayed(); 11 } 12 }