一、@FindBy和@CacheLookup用法
代碼執行個體
package page;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
public class BDPage {
@FindBy(id="kw")
@CacheLookup
public WebElement keyword_input;
@FindBy(id="su")
@CacheLookup
public WebElement search_button;
public BDPage(WebDriver driver){
PageFactory.initElements(driver, this);
}
}
元素聲明的寫法,這三行是一個整體:
@FindBy(id="kw")
@CacheLookup
public WebElement keyword_input;
注解:
@FindBy:這個定義了你所查找的元素是以什麼方式 定位的,比如圖中我用的是id,那麼就寫成 @FindBy(id=”kw”),
還有其他幾種寫法:@FindBy(name=”xx”)、@FindBy(className=”xx”)、@FindBy(xpath=”xxx”)、@FindBy(css=”xxx”)等
@CacheLookup:意思是說找到元素之後将緩存元素,重複的使用這些元素,将使測試的速度大大加快。
WebElement keyword_input:就是變量名
二、PageFactory
public BDPage(WebDriver driver){
PageFactory.initElements(driver, this);
}
PageFactory是為了支援頁面設計模式而開發出來的,它的方法在selenium.support庫裡面。
它提供初始化頁面元素的方法,如果頁面存在大量的AJAX的技術,隻要頁面更新一次,它就好重新查找一次元素,是以不
會出現StaleElementException這個error,
頁面設計模式,可以提供你一個接口,然後你在這個接口上面,建構你自己項目中的頁面對象,使用PageFactory使得測
試更簡單,更少的代碼編寫。
如果@FindBy沒有指定,它會預設的查找id的屬性,然後是name屬性,如果還沒有找到就會報錯。 如果這個元素存在,
我們不用擔心它, pageFactory會初始化這個元素,不會報任何錯誤。
二、selenium流行的設計模式page object
selenium目前比較流行的設計模式就是page object,那麼到底什麼是page object呢,簡單來說,就是把頁面作為對象,
在使用中傳遞頁面對象,來使用頁面對象中相應的成員或者方法,能更好的提現java的面向對象和封裝特性。而使用時間長了
會發現該模式也存在一點問題,那就是元素每次都要擷取,并且擷取元素與頁面方法不分離,增加代碼備援度,用過springMVC架構
的人都知道,注解方式的開發會大大增加開發效率,使頁面變得整潔。
本次要介紹的就是pageFactory 設計模式,什麼是pageFactory 設計模式呢?
準确來說就是在page object模式基礎上更好的利用了面向對象的思維,将擷取元素與操作頁面的方法進行分離,以前擷取
元素要findelementbyid等等,現在隻要一個注解就可以搞定,并且再次跑自動化回歸測試時候,代碼有擷取緩存的特性,
是以會比第一次跑的快,隻要id,name不變。
1.首先介紹FindBy類:
For example, these two annotations point to the same element:
@FindBy(id = "f") WebElement f;
@FindBy(how = How.ID, using = "f") WebElement f;
and these two annotations point to the same list of elements:
@FindBy(tagName = "a") List<WebElement> links;
@FindBy(how = How.TAG_NAME, using = "a") List<WebElement> links;
用來分别查找單個元素和多個元素的兩種用法,支援的類型有:className、css、id、linkText、name、
partialLinkText、tagName、xpath。
How支援的類型和上面差不多。
2.接着介紹PageFactory類
Factory class to make using Page Objects simpler and easier.
它提供的方法都是靜态的,可以直接調用,我們在用完findby後,需要進行元素初始化,則需要調用下面的方法
initElements(ElementLocatorFactory factory, java.lang.Object page)、initElements(FieldDecorator
decorator, java.lang.Object page)、initElements(WebDriver driver, java.lang.Class<T> pageClassToProxy)、
initElements(WebDriver driver, java.lang.Object page)
我們在實際使用中可以這樣用:
PageFactory.initElements(dr, XXX.class);
或者
PageFactory.initElements(new AjaxElementLocatorFactory(dr, 10) ,XXX.class);
後者加入了初始化元素時等待時間。
3.下面給大家簡單用個例子介紹我的設計模式。
public class BasePage {
WebDriver driver;
private final int TIMEOUT=3;
public BasePage(WebDriver driver )
{
this.driver=driver;
PageFactory.initElements(new AjaxElementLocatorFactory(driver, TIMEOUT) , this);
}
public BasePage(WebDriver driver,final String title)
{
this.driver=driver;
WebDriverWait wait=new WebDriverWait(driver, TIMEOUT);
try{
boolean flag = wait.until(new ExpectedCondition<Boolean>(){
@Override
public Boolean apply(WebDriver arg0) {
// TODO Auto-generated method stub
String acttitle = arg0.getTitle();
return acttitle.equals(title);
}});
}catch(TimeoutException te) {
throw new IllegalStateException("目前不是預期頁面,目前頁面title是:" + driver.getTitle());
}
PageFactory.initElements(new AjaxElementLocatorFactory(driver, TIMEOUT) , this);
}
這是我的基礎頁面,以後任何頁面都繼承該頁面,因為判斷UI層次的頁面标題。
2.登入頁面
public class LoginPage extends BasePage {
@FindBy(id="ele_active_close")
@CacheLookup
private WebElement wd;
@FindBy(id="at_index_login-box_mobile")
@CacheLookup
private WebElement inputusername;
@FindBy(id="at_index_login-box_password")
@CacheLookup
private WebElement inputpassword;
@FindBy(id="at_index_login-box_p_forget_login")
@CacheLookup
private WebElement mybutton;
public LoginPage(WebDriver driver) {
// TODO Auto-generated constructor stub
super(driver);
}
public LoginPage(WebDriver driver, String title) {
super(driver, title);
// TODO Auto-generated constructor stub
}
//不設定homepage類型不行,因為傳回的是這個對象 必須是這個類型
public HomePage login(){
JbClose();
username("");
password("");
mybutton();
return new HomePage(driver,"xxx);
}
public void username(String username)
{
inputusername.clear();
inputusername.sendKeys(username);
}
public void password(String password)
{
inputpassword.clear();
inputpassword.sendKeys(password);
}
public void mybutton()
{
mybutton.click();
}
public void JbClose()
{
wd.click();
}
}
3.登入後要進入什麼頁面
public class HomePage extends BasePage{
public HomePage(WebDriver driver) {
super(driver);
// TODO Auto-generated constructor stub
}
public HomePage(WebDriver driver,String title)
{
super(driver,title);
}
}
4.下面就是main方法了,實際中建議和testng混合使用
public class TestFactory {
public static void main(String[] args) {
WebDriver driver=new ChromeDriver();
driver.get("http://petrocoke-web-test.obaymax.com/");
String logintitle="xxx";
LoginPage lg=new LoginPage(driver, logintitle);
HomePage hm=lg.login();
System.out.println("測試結束");
driver.quit();
}
}
三、selenium之設計模式POM
前面介紹了POM的優點和非POM方式寫腳本,這篇介紹利用頁面工廠類(page factory)去實作POM,
通過檢視PageFactory類,我們可以知道它是一個初始化一個頁面執行個體的功能,在執行個體化該頁面對象時候,
也會一起執行個體化該頁面的元素定位。直接來看看京東登入的例子,如果用POM實作,在測試腳本中實際代碼就2行。
1.在pageObjects包建立一個京東首頁類,代碼如下
package pageObects;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
public class JdHomePage {
// 元素定位
//登入連結
@FindBy (id="ttbar-login")
WebElement login_link;
//賬戶登入
@FindBy (xpath="//*/div[@class='login-form']/div[2]/a")
WebElement login_withAccount;
//輸入使用者名框
@FindBy (id="loginname")
WebElement inputBox_username;
//輸入密碼
@FindBy (id="nloginpwd")
WebElement inputBox_password;
//登入按鈕
@FindBy (id="loginsubmit")
WebElement login_submitBtn;
// 業務邏輯和操作方法
//登入方法
public void login(String username, String password){
login_link.click();
login_withAccount.click();
inputBox_username.sendKeys(username);
inputBox_password.sendKeys(password);
login_submitBtn.click();
}
}
2.在testSuites包下建立一個測試類
package testSuites;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.PageFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import pageObects.JdHomePage;
public class TestWithPOM {
WebDriver driver;
@BeforeClass
public void setUp() throws Exception{
System.setProperty("webdriver.chrome.driver", ".\\Tools\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://www.jd.com/");
Thread.sleep(2000);
}
@Test
public void testLogin(){
JdHomePage hp = PageFactory.initElements(driver, JdHomePage.class);
hp.login("user1", "123456");
}
}
處理打開浏覽器和打開京東首頁操作,實際測試登入的代碼就2行對不對。這裡我們借助了PageFactory類的方法,在初始化一
個頁面類的時候,也會一起把該頁面定義的元素定位也會初始化,然後通過頁面對象調用頁面類的頁面操作方法。這種方式,我們把元素
定位和業務邏輯操作都寫在了頁面對象類中,測試腳本類,直接調用頁面類的方法,這樣的測試腳本看起來很簡潔,友善閱讀和維護,如果
登入相關文案發生變更,我們隻需要去改登入對應頁面的元素定位和業務邏輯,不需要修改這個登入測試類。